diff --git a/LICENSE b/LICENSE index 58aaa3e0d..2c552a360 100644 --- a/LICENSE +++ b/LICENSE @@ -1744,3 +1744,55 @@ Download: https://github.com/kmackay/micro-ecc.git ======================================================================== + +20. License of multi_webcamera host + +======================================================================== +examples/multi_webcamera/host/linux_video + +This software is used on linux and distributed subject to the licensing +described in the following file: + + examples/multi_webcamera/host/linux_video/LICENSE + + +examples/multi_webcamera/host/python + +This script is used on linux and distributed subject to the following +licensing descriiption: + +BSD-3-Clause +------------------------------------------------------------------------ + Copyright 2019, 2020 Sony Semiconductor Solutions Corporation + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. +3. Neither the name of Sony Semiconductor Solutions Corporation nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +------------------------------------------------------------------------ + +======================================================================== + diff --git a/examples/Make.defs b/examples/Make.defs deleted file mode 100644 index d966900cd..000000000 --- a/examples/Make.defs +++ /dev/null @@ -1,83 +0,0 @@ -############################################################################ -# Common make definitions provided to all applications -# -# Copyright (C) 2011, 2014, 2016 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -# Builtin Registration - -BUILTIN_REGISTRY = $(SDKDIR)$(DELIM)system$(DELIM)builtin$(DELIM)registry - -DEPCONFIG = $(SDKDIR)$(DELIM).config - -ifeq ($(CONFIG_WINDOWS_NATIVE),y) -define REGISTER - $(Q) echo Register: $1 - $(Q) echo { "$1", $2, $3, $4 }, > "$(BUILTIN_REGISTRY)$(DELIM)$4.bdat" - $(Q) echo int $4(int argc, char *argv[]); > "$(BUILTIN_REGISTRY)$(DELIM)$4.pdat" - $(Q) touch $(BUILTIN_REGISTRY)$(DELIM).updated" -endef -else -define REGISTER - $(Q) echo "Register: $1" - $(Q) echo "{ \"$1\", $2, $3, $4 }," > "$(BUILTIN_REGISTRY)$(DELIM)$4.bdat" - $(Q) echo "int $4(int argc, char *argv[]);" > "$(BUILTIN_REGISTRY)$(DELIM)$4.pdat" - $(Q) touch "$(BUILTIN_REGISTRY)$(DELIM).updated" -endef -endif - -# Tools - -ifeq ($(CONFIG_WINDOWS_NATIVE),y) - MKKCONFIG = $(SDKDIR)\tools\mkkconfig.bat - DIRLINK = $(TOPDIR)\tools\link.bat - DIRUNLINK = $(TOPDIR)\tools\unlink.bat -else - MKKCONFIG = $(SDKDIR)/tools/mkkconfig.sh - DIRUNLINK = $(TOPDIR)/tools/unlink.sh -ifeq ($(WINTOOL),y) - DIRLINK = $(TOPDIR)/tools/copydir.sh -else - DIRLINK = $(TOPDIR)/tools/link.sh -endif -endif - -# Standard include path - -CFLAGS += ${INCDIR_PREFIX}$(SDKDIR)$(DELIM)bsp$(DELIM)include -CXXFLAGS += ${INCDIR_PREFIX}$(SDKDIR)$(DELIM)bsp$(DELIM)include -CFLAGS += ${INCDIR_PREFIX}$(SDKDIR)$(DELIM)system$(DELIM)include -CXXFLAGS += ${INCDIR_PREFIX}$(SDKDIR)$(DELIM)system$(DELIM)include - -# utility - -dequoted = $(subst ",,$1) diff --git a/examples/audio_beep/Makefile b/examples/audio_beep/Makefile index 859c86727..7c6eab1a8 100644 --- a/examples/audio_beep/Makefile +++ b/examples/audio_beep/Makefile @@ -47,14 +47,8 @@ MODULE = $(CONFIG_EXAMPLES_AUDIO_BEEP) MAINSRC = audio_beep_main.cxx -# Audio Example paths - -AUDIODIR = $(SDKDIR)$(DELIM)modules$(DELIM)audio - # Audio Example flags -CXXFLAGS += ${INCDIR_PREFIX}$(AUDIODIR) - CXXFLAGS += -D_POSIX include $(APPDIR)/Application.mk diff --git a/examples/audio_dual_players/Makefile b/examples/audio_dual_players/Makefile index e87e087f0..b13457c9a 100644 --- a/examples/audio_dual_players/Makefile +++ b/examples/audio_dual_players/Makefile @@ -47,14 +47,8 @@ MODULE = $(CONFIG_EXAMPLES_AUDIO_DUAL_PLAYERS) MAINSRC = audio_dual_players_main.cxx -# Audio Example paths - -#AUDIODIR = $(SDKDIR)$(DELIM)modules$(DELIM)audio - # Audio Example flags -# XXX: Do NOT add module directory, please use modules/include. -#CXXFLAGS += ${INCDIR_PREFIX}$(AUDIODIR) CXXFLAGS += -D_POSIX CXXFLAGS += -DUSE_MEMMGR_FENCE CXXFLAGS += -DATTENTION_USE_FILENAME_LINE diff --git a/examples/audio_oscillator/Makefile b/examples/audio_oscillator/Makefile index df9590b4c..c97482c76 100644 --- a/examples/audio_oscillator/Makefile +++ b/examples/audio_oscillator/Makefile @@ -54,7 +54,6 @@ AUDIODIR = $(SDKDIR)$(DELIM)modules$(DELIM)audio # Audio oscillator Example flags -CXXFLAGS += ${INCDIR_PREFIX}$(AUDIODIR) CXXFLAGS += ${INCDIR_PREFIX}$(AUDIODIR)$(DELIM)include CXXFLAGS += ${INCDIR_PREFIX}worker_oscillator$(DELIM)userproc$(DELIM)include ifeq ($(CONFIG_EXAMPLES_AUDIO_OSCILLATOR_USEPOSTPROC),y) diff --git a/examples/audio_pcm_capture/Makefile b/examples/audio_pcm_capture/Makefile index b2d525ec6..1a7c2d178 100644 --- a/examples/audio_pcm_capture/Makefile +++ b/examples/audio_pcm_capture/Makefile @@ -47,13 +47,8 @@ MODULE = $(CONFIG_EXAMPLES_AUDIO_PCM_CAPTURE) MAINSRC = audio_pcm_capture_main.cxx -# Audio Example paths - -AUDIODIR = $(SDKDIR)$(DELIM)modules$(DELIM)audio - # Audio Example flags -CXXFLAGS += ${INCDIR_PREFIX}$(AUDIODIR) CXXFLAGS += -D_POSIX CXXFLAGS += -DUSE_MEMMGR_FENCE CXXFLAGS += -DATTENTION_USE_FILENAME_LINE diff --git a/examples/audio_pcm_capture_objif/Makefile b/examples/audio_pcm_capture_objif/Makefile index b5de9c3cf..ceb860acd 100644 --- a/examples/audio_pcm_capture_objif/Makefile +++ b/examples/audio_pcm_capture_objif/Makefile @@ -47,14 +47,8 @@ MODULE = $(CONFIG_EXAMPLES_AUDIO_PCM_CAPTURE_OBJIF) MAINSRC = audio_pcm_capture_objif_main.cxx -# Audio Example paths - -AUDIODIR = $(SDKDIR)$(DELIM)modules$(DELIM)audio - # Audio Example flags -CXXFLAGS += ${INCDIR_PREFIX}$(AUDIODIR) - CXXFLAGS += -D_POSIX CXXFLAGS += -DUSE_MEMMGR_FENCE CXXFLAGS += -DATTENTION_USE_FILENAME_LINE diff --git a/examples/audio_player/Makefile b/examples/audio_player/Makefile index fac878407..7bc90529d 100644 --- a/examples/audio_player/Makefile +++ b/examples/audio_player/Makefile @@ -47,13 +47,8 @@ MODULE = $(CONFIG_EXAMPLES_AUDIO_PLAYER) MAINSRC = audio_player_main.cxx -# Audio Example paths - -AUDIODIR = $(SDKDIR)$(DELIM)modules$(DELIM)audio - # Audio Example flags -CXXFLAGS += ${INCDIR_PREFIX}$(AUDIODIR) ifeq ($(CONFIG_EXAMPLES_AUDIO_PLAYER_USEPOSTPROC),y) CXXFLAGS += ${INCDIR_PREFIX}worker$(DELIM)userproc$(DELIM)include endif diff --git a/examples/audio_player_objif/Makefile b/examples/audio_player_objif/Makefile index bbea845dd..a3060f8ee 100644 --- a/examples/audio_player_objif/Makefile +++ b/examples/audio_player_objif/Makefile @@ -47,13 +47,8 @@ MODULE = $(CONFIG_EXAMPLES_AUDIO_PLAYER_OBJIF) MAINSRC = audio_player_objif_main.cxx -# Audio Example paths - -AUDIODIR = $(SDKDIR)$(DELIM)modules$(DELIM)audio - # Audio Example flags -CXXFLAGS += ${INCDIR_PREFIX}$(AUDIODIR) ifeq ($(CONFIG_EXAMPLES_AUDIO_PLAYER_OBJIF_USEPOSTPROC),y) CXXFLAGS += ${INCDIR_PREFIX}worker$(DELIM)userproc$(DELIM)include endif diff --git a/examples/audio_recognizer/Makefile b/examples/audio_recognizer/Makefile index 1646be3d6..fa734cfcd 100644 --- a/examples/audio_recognizer/Makefile +++ b/examples/audio_recognizer/Makefile @@ -47,13 +47,8 @@ MODULE = $(CONFIG_EXAMPLES_AUDIO_RECOGNIZER) MAINSRC = audio_recognizer_main.cxx -# Audio Example paths - -AUDIODIR = $(SDKDIR)$(DELIM)modules$(DELIM)audio - # Audio Example flags -CXXFLAGS += ${INCDIR_PREFIX}$(AUDIODIR) CXXFLAGS += ${INCDIR_PREFIX}worker_recognizer$(DELIM)userproc$(DELIM)include ifeq ($(CONFIG_EXAMPLES_AUDIO_RECOGNIZER_USEPREPROC),y) CXXFLAGS += ${INCDIR_PREFIX}worker_preprocess$(DELIM)userproc$(DELIM)include diff --git a/examples/audio_recorder/Makefile b/examples/audio_recorder/Makefile index c0765a2c7..bd4b30be5 100644 --- a/examples/audio_recorder/Makefile +++ b/examples/audio_recorder/Makefile @@ -48,13 +48,8 @@ MODULE = $(CONFIG_EXAMPLES_AUDIO_RECORDER) CXXSRCS = audio_util.cxx MAINSRC = audio_recorder_main.cxx -# Audio Example paths - -AUDIODIR = $(SDKDIR)$(DELIM)modules$(DELIM)audio - # Audio Example flags -CXXFLAGS += ${INCDIR_PREFIX}$(AUDIODIR) ifeq ($(CONFIG_EXAMPLES_AUDIO_RECORDER_USEPREPROC),y) CXXFLAGS += ${INCDIR_PREFIX}worker$(DELIM)userproc$(DELIM)include endif diff --git a/examples/audio_recorder_objif/Makefile b/examples/audio_recorder_objif/Makefile index 3a9f23e40..0734499a0 100644 --- a/examples/audio_recorder_objif/Makefile +++ b/examples/audio_recorder_objif/Makefile @@ -47,13 +47,8 @@ MODULE = $(CONFIG_EXAMPLES_AUDIO_RECORDER_OBJIF) MAINSRC = audio_recorder_objif_main.cxx -# Audio Example paths - -AUDIODIR = $(SDKDIR)$(DELIM)modules$(DELIM)audio - # Audio Example flags -CXXFLAGS += ${INCDIR_PREFIX}$(AUDIODIR) ifeq ($(CONFIG_EXAMPLES_AUDIO_RECORDER_OBJIF_USEPREPROC),y) CXXFLAGS += ${INCDIR_PREFIX}worker$(DELIM)userproc$(DELIM)include endif diff --git a/examples/audio_sound_effector/Makefile b/examples/audio_sound_effector/Makefile index 70833e4e4..350204f94 100644 --- a/examples/audio_sound_effector/Makefile +++ b/examples/audio_sound_effector/Makefile @@ -47,14 +47,8 @@ MODULE = $(CONFIG_EXAMPLES_AUDIO_SOUND_EFFECTOR) MAINSRC = audio_sound_effector.cxx -# Audio Example paths - -AUDIODIR = $(SDKDIR)$(DELIM)modules$(DELIM)audio - # Audio Example flags -CXXFLAGS += ${INCDIR_PREFIX}$(AUDIODIR) - CXXFLAGS += -D_POSIX CXXFLAGS += -DUSE_MEMMGR_FENCE CXXFLAGS += -DATTENTION_USE_FILENAME_LINE diff --git a/examples/audio_through/Makefile b/examples/audio_through/Makefile index 6ff6ed977..cb836cab4 100644 --- a/examples/audio_through/Makefile +++ b/examples/audio_through/Makefile @@ -47,14 +47,8 @@ MODULE = $(CONFIG_EXAMPLES_AUDIO_THROUGH) MAINSRC = audio_through_main.cxx -# Audio Example paths - -AUDIODIR = $(SDKDIR)$(DELIM)modules$(DELIM)audio - # Audio Example flags -CXXFLAGS += ${INCDIR_PREFIX}$(AUDIODIR) - CXXFLAGS += -D_POSIX CXXFLAGS += -DUSE_MEMMGR_FENCE CXXFLAGS += -DATTENTION_USE_FILENAME_LINE diff --git a/examples/audiolite_fft/.gitignore b/examples/audiolite_fft/.gitignore new file mode 100644 index 000000000..9c76071ab --- /dev/null +++ b/examples/audiolite_fft/.gitignore @@ -0,0 +1,12 @@ +/Make.dep +/.depend +/.built +/*.asm +/*.obj +/*.rel +/*.lst +/*.sym +/*.adb +/*.lib +/*.src +/*.spk diff --git a/examples/audiolite_fft/Kconfig b/examples/audiolite_fft/Kconfig new file mode 100644 index 000000000..c65e963f4 --- /dev/null +++ b/examples/audiolite_fft/Kconfig @@ -0,0 +1,26 @@ + +config EXAMPLES_AUDIOLITE_FFT + tristate "AudioLite sample : audiolite_fft app" + default n + ---help--- + Enable the audiolite_fft app. This example includes how to make + user original audiolite component with worker (sub-core) off-load. + +if EXAMPLES_AUDIOLITE_FFT + +config EXAMPLES_AUDIOLITE_FFT_PROGNAME + string "Program name" + default "audiolite_fft" + ---help--- + This is the name of the program that will be use when the NSH ELF + program is installed. + +config EXAMPLES_AUDIOLITE_FFT_PRIORITY + int "audiolite_fft task priority" + default 100 + +config EXAMPLES_AUDIOLITE_FFT_STACKSIZE + int "audiolite_fft stack size" + default 2048 + +endif diff --git a/examples/audiolite_fft/Make.defs b/examples/audiolite_fft/Make.defs new file mode 100644 index 000000000..99a9597bb --- /dev/null +++ b/examples/audiolite_fft/Make.defs @@ -0,0 +1,4 @@ + +ifneq ($(CONFIG_EXAMPLES_AUDIOLITE_FFT),) +CONFIGURED_APPS += audiolite_fft +endif diff --git a/examples/audiolite_fft/Makefile b/examples/audiolite_fft/Makefile new file mode 100644 index 000000000..bd4d390e9 --- /dev/null +++ b/examples/audiolite_fft/Makefile @@ -0,0 +1,26 @@ + +include $(APPDIR)/Make.defs +include $(SDKDIR)/Make.defs + +PROGNAME = $(CONFIG_EXAMPLES_AUDIOLITE_FFT_PROGNAME) +PRIORITY = $(CONFIG_EXAMPLES_AUDIOLITE_FFT_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_AUDIOLITE_FFT_STACKSIZE) +MODULE = $(CONFIG_EXAMPLES_AUDIOLITE_FFT) + +ASRCS = +CSRCS = +MAINSRC = audiolite_fft_main.cxx + +CXXSRCS += alusr_fftworker.cxx + +include $(APPDIR)/Application.mk + +build_fftworker_worker: + @$(MAKE) -C fftworker TOPDIR="$(TOPDIR)" SDKDIR="$(SDKDIR)" APPDIR="$(APPDIR)" CROSSDEV=$(CROSSDEV) + +clean_fftworker_worker: + @$(MAKE) -C fftworker TOPDIR="$(TOPDIR)" SDKDIR="$(SDKDIR)" APPDIR="$(APPDIR)" CROSSDEV=$(CROSSDEV) clean + +$(OBJS): build_fftworker_worker + +clean:: clean_fftworker_worker diff --git a/examples/audiolite_fft/README.md b/examples/audiolite_fft/README.md new file mode 100644 index 000000000..fdbb786f8 --- /dev/null +++ b/examples/audiolite_fft/README.md @@ -0,0 +1,1197 @@ +> [!NOTE] +> This tutorial is written in [English section](#english-section) after Japanese section. + +## AudioLite オリジナルコンポーネント作成チュートリアル + +### 概要説明 + +このチュートリアルでは、Spresense SDK で提供されているmkalwcomp.pyを用いて、 +AudioLiteでサブコアを用いた独自の信号処理を実装するための説明を行います。 +このチュートリアルを通して、audiolite_fftサンプルコードと全く同じ動作をするアプリを作成します。 + +AudioLiteはコンポーネントと呼ばれる機能モジュールを組み合わせることで、 +アプリケーションが行いたいAudioの信号処理のデータフローをランタイムに構築し、 +実行するためのフレームワークです。 + + +コンポーネント接続例:マイク入力からの音に対して、信号処理を行い、スピーカーに出力 +![Component](images/component.png) + + +コンポーネントはユーザーも自由に作成することが出来、作成したコンポーネントを、 +信号処理のデータフローに組み込むことでオリジナルな信号処理を追加することが出来ます。 + +コンポーネントは内部でSpresenseが持つサブコアを利用することで、 +処理をオフロードすることも出来ます。 + +Worker(SubCore)を用いたコンポーネント +![WorkerComponent](images/worker_component.png) + + +#### mkalwcomp.py コマンド + +上記の図にある、 **ユーザーオリジナルコンポーネント(サブコア付き)** と **Worker(SubCore)** のペアの実装のテンプレート出力をするツールが、 +**mkalcomp.py** になります。 + +#### 作成するプログラム + +このチュートリアルでは、mkalwcomp.py コマンドを用いてコンポーネントのテンプレートコードを出力し、 +FFTを行って、音の周波数解析をUARTで出力するプログラムを作成します。 + +### 作成するコンポーネントの設計 + +まず、どのような信号処理を行うコンポーネントを作成するかですが、 +入力されたAudioのサンプルにFFTで周波数成分に直し、スペクトル強度を算出して +出力する、というコンポーネントにします。 + +FFTは信号の一部を切り出して、その信号が周期的な信号であると仮定して周波数分析を行う手法です。 +したがって、切り出した信号の両端がスムーズに連携していないと実在しない高周波成分が乗ってしまうことになります。 +そこで、窓関数を掛けて、周期的に連続するような信号に加工してからFFTをかけるのが一般的です。 +窓関数には色々ありますが、よく使われる窓関数の一つ、Hanning窓を利用します。 [参考](https://en.wikipedia.org/wiki/Window_function) + +ただし、窓関数をかけると切り出した信号の両端の信号が礫れしまいます。 +この副作用を抑えるためによく用いられる手法として、切り出すサイズを半分づつずらしてFFTをかけます。 +これによって、潰れる信号を極力抑えることが可能となります。 + +以上のことから、 +FFTを行うコンポーネントの信号処理の概要は以下のような仕様になります。 + +![FFT Component](images/fft_component_outline.png) + +計算し終わったパワースペクトラムを後段のコンポーネントに渡します。 +パワースペクトラムは、FFTサイズに対して半分のデータ数となります。 +FFTの計算が終わったら、次の入力データ用に図の **FFT 入力データ** の上半分を消し下半分のデータを上にシフトさせ、 +新たな入力データに備えます。 + +今回は演算部分をSubcore(SDKではWorkerと呼びます)で行います。 +そのため、Workerは入力 Audio Sample Dataが格納されたメモリと演算結果の出力メモリを、自作するAudioLite Componentから受け取り、 +入力メモリを使い終わった、もしくは出力メモリに結果を書き終わったら、それぞれのメモリをComponentに戻し、 +Component側はそれぞれを次のコンポーネントに渡します。 + +### コンポーネントのテンプレート作成 + +それでは、まずはコンポーネントのテンプレートを作成しましょう。 +なお、現時点(Spresense SDK v3.3.0)では、これらのコマンドはCLI環境でのみ動作します。 +VSCodeを用いている場合、VSCode内でターミナルを開き、spresenseディレクトリに移動してください。 + +#### ツール郡のパスを通す。 + +まずは、ツールを利用する上で、そのツールのパスを通す必要があります。 + +spresense/sdkディレクトリに移動し、プロンプトから以下のコマンドを実行してください。 + +```shell +source tools/build-env.sh +``` + +これで必要なツールが利用できるようになりました。 + +#### NuttShell コマンドコードの作成 + +続いてNuttShellのコマンドを作成します。 +> [!NOTE] +> NuttShellのコマンドとは、ビルド後、nuttx.spkを焼き込んだ後、実機側のターミナルプロンプト ```nsh> ``` で入力するコマンドのことです。 + +同じくspresense/sdkディレクトリの中で、以下のコマンドを実行します。 +今回のコマンド名は、 **alfft** とします。 + +```shell +./tools/mkcmd.py -x alfft +``` + +mkcmd.pyはNuttShellのコマンド実装のテンプレートコードを生成してくれるコマンドです。 +オプション引数 ```-x``` は、C++のテンプレートを生成することを意味しています。 +その後の ```alfft``` がコマンド名となります。 +> [!NOTE] +> AudioLiteはC++のライブラリのため、C++のテンプレートを出力するようにします。 + +このコマンドを実行すると、spresense/examplesディレクトリ以下にalfftというディレクトリが出来、 +その中にビルドに必要なMakefileを含むテンプレートファイル群が生成されます。 + +spresense/examples/alfftディレクトリに移動し、lsコマンドで生成されたファイル群を見てみてください。 + +```shell +cd ../examples/alfft +ls +``` + +すると、以下のようなファイルが見えます。 + +``` +Kconfig Make.defs Makefile alfft_main.cxx configs/ +``` + +これらのファイルの内容は以下の表にまとめておきます。 + +| File名 | 内容 | +| -------------- | ---- | +| Kconfig | このコマンドをビルド対象とするかしないかを選択するConfig用の定義ファイル。(デフォルトはビルド対象とするようになっている) | +| Make.defs | ビルドシステムが利用するファイル | +| Makefile | 実際にビルド対象となるソースコードファイルやGCCの引数などのオプションを記載するファイル | +| alfft_main.cxx | 今回作成するalfftコマンドのエントリー関数(main()関数)が実装されるソースファイル | +| configs/ | このコマンド特有のConfig設定を保存するためのフォルダ | + + +#### AudioLite ComponentとそのWorkerテンプレートの生成 + +作成したalfftコマンドの中で、FFTを行うWorkerとそれを制御するオリジナルなAudioLite Componentを作成します。 + +先程移動した、spresense/examples/alfftの中で、以下のコマンドを実行してください。 + +```shell +mkalwcomp.py fft +``` + +このコマンドを実行すると、以下のようなログが出力されます。 + +``` +=== Generating audiolite worker component in . + [G] Generate ./fft/Makefile + [G] Generate ./fft/.gitignore + [G] Generate ./fft/alworker_commfw_config.h + [G] Generate ./fft/fft_worker_main.h + [G] Generate ./fft/fft_worker_main.c + [G] Generate ./alusr_fft.h + [G] Generate ./alusr_fft.cxx + [C] Save ./Makefile to ./Makefile_org + [M] Modify ./Makefile +Done in successfly +``` + +結果として、spresense/examples/alfftの下に、 AudioLite Componentのコードが生成されると同時に、 +fftというサブフォルダに、Worker側の独立したバイナリを作成するために必要なコードが作成されます。 + +```shell +ls +``` + +lsの実行結果 +``` +Kconfig Make.defs Makefile Makefile_org alfft_main.cxx alusr_fft.cxx alusr_fft.h configs/ fft/ +``` + +```shell +ls fft +``` + +ls fftの実行結果 +``` +Makefile alworker_commfw_config.h fft_worker_main.c fft_worker_main.h +``` + +生成されたファイルとその内容を以下の表にまとめておきます。 + +| File名 | 内容 | +| ---------------------------- | ---- | +| alusr_fft.cxx | Workerであるfftと連携するAudioLite Componentのクラス実装 | +| alusr_fft.h | alusr_fftクラスのヘッダファイル | +| Makefile_org | 元のMakefileのコピー。mkalwcomp.pyは、alusr_fft.cxxとworkerのビルドを行えるようMakefileを修正している | +| fft/Makefile | fft worker 側のビルドを行うためのビルドスクリプト | +| fft/alworker_commfw_config.h | audiolite workerを手軽に実装できるようにしたフレームワークの設定ファイル | +| fft/fft_worker_main.c | fft workerのソースコード(C言語) | +| fft/fft_worker_main.h | fft workerとalusr_fftコンポーネントとの共通情報を記載するためのヘッダファイル | + +### 実装 + +テンプレートファイルが生成されたので、 +実際に目的の信号処理を行うコードの実装を行います。 + +生成されたテンプレートファイルの中で、今回のチュートリアルで編集するファイルと編集内容は以下のようになります。 + +| 編集するFile名 | 内容 | +| ---------------------------- | ---- | +| fft/fft_worker_main.h | fft workerとalusr_fftコンポーネントとの共通情報として、FFTのサイズの定義を記載する | +| fft/fft_worker_main.c | 信号処理を実装する。入力Audio Sample DataをFFTを行うサイズに切り取ってFFTを掛け、出力メモリに出力する | +| alusr_fft.cxx | Workerに渡す出力用メモリのサイズをFFTの出力サイズに変更する | +| alfft_main.cxx | alusr_fftをaudioliteのマイク入力コンポーネントと組み合わせてFFT結果をコンソール出力するアプリの大枠の実装を行う | + +> [!NOTE] +> 実装の説明に入る前に、[memblk_t](#memblk_t) の章をを読んでおいてください。 +> ComponentからWorkerへ送られるメモリは、 memblk_tという構造体にラップして扱います。 +> この構造体は、メモリのアドレスを管理するだけでなく、溜まっているデータをどの程度消費したか(使ったか)、 +> また、空のメモリに対してどの程度データを溜めたか、などの管理を容易にするための構造体です。 +> [memblk_t](#memblk_t)の章でその使い方を詳しく解説しています。 + +#### fft/fft_worker_main.hの編集 + +ではまず、alusr_fftコンポーネントとfft workerで共通の情報をfft/fft_worker_main.hに記述します。 +生成された直後のファイルの中身は以下のようになっています。 + +```c:fft/fft_worker_main.h +#ifndef __AUDIOLITE_WORKER_USR_FFT_H +#define __AUDIOLITE_WORKER_USR_FFT_H + +/* Add a common definition between worker and the audiolite component here */ + +#define FFT_WORKER_VERSION (1) + +#endif /* __AUDIOLITE_WORKER_USR_FFT_H */ +``` + +これに対して、FFTのサイズ:FFT TAP数と、その半分の値の定義を記載します。 +固定の整数値の定義となるので、defineマクロを用いて、以下のように記載します。 + +```c +#define FFT_TAPS (512) +#define FFT_TAPSHALF (FFT_TAPS / 2) +``` + +これをfft/fft_worker_main.hに追記します。 +編集した結果、以下のようになります。 + +```c:fft/fft_worker_main.h +#ifndef __AUDIOLITE_WORKER_USR_FFT_H +#define __AUDIOLITE_WORKER_USR_FFT_H + +/* Add a common definition between worker and the audiolite component here */ + +#define FFT_WORKER_VERSION (1) + +#define FFT_TAPS (512) +#define FFT_TAPSHALF (FFT_TAPS / 2) + +#endif /* __AUDIOLITE_WORKER_USR_FFT_H */ +``` + +これで、fft/fft_worker_main.hの編集は完了です。 + +#### fft/fft_worker_main.cの編集 + +それでは、信号処理本体の実装に入ります。 +まず、編集前のfft/fft_worker_main.cの中身は以下のようになります。 +(一部抜粋しています。) + +```c:fft/fft_worker_main.c +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include "fft_worker_main.h" + +/**************************************************************************** + * Private Data Types + ****************************************************************************/ + +struct my_worker_instance_s +{ + /* ALWORKERCOMMFW_INSTANCE should be on top of your instance */ + + ALWORKERCOMMFW_INSTANCE; + + /* Add specific items for your application here */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct my_worker_instance_s g_instance; + +// ... <抜粋> ... + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +// ... <抜粋> ... + +static int on_process(void *arg) +{ +// ... <抜粋> ... +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(void) +{ +// ... <抜粋> ... +} +``` + +このファイルでは、ヘッダのインクルードをした後、このWorkerの独自の構造体、```struct my_worker_instance_s``` が定義され、 +その後、その構造体のインスタンス、```g_instance``` 変数が定義されています。 +その後、on_process()関数と、main()関数が記述されています。 + +on_process()関数は、Workerの起動が始まり、Componentから信号処理開始指示が来ると実行される関数になります。 +Componentから終了指示が来るまで、on_process()が呼ばれ続けます。(arduinoのloop()に似ています。) +main()関数は、Workerのエントリ関数で、Workerがメモリにロードされると実行される関数になります。 +この関数では、各種初期化を行い、その後、alworker_commfw_msgloop()を呼び出すことで、Componentからの指示にしたがって適宜処理を行います。 + +今回、FFTの演算には、ARM社製のCMSISライブラリを用います。 +そのため、まずはヘッダファイルとして、arm_math.hをインクルードしておきます。 +```c +#include +#include +#include "fft_worker_main.h" + +#include "arm_math.h" /* 追加 */ +``` + +データパスの設計ですが、信号処理の概要として記載した図に対して、更に具体的になデータパスは以下のようになります。 + +![FFT Component詳細](images/fft_component_detail.png) + +入力Audio Sample Dataと出力用メモリは任意のサイズでComponentから送られてきます。 +入力Sampleは2chのステレオデータで来るため、これを1ch分でFFT_TAPSHALFサイズ分になるまでPCM Cacheに蓄えます。 +PCM Cacheがいっぱいになったら、これを16bit整数から32bit 浮動小数点に変換を行いながらPCM Floatメモリにコピーします。 +その後、窓関数を掛けてFFTを行い、パワースペクトルを算出します。最後に最大値で正規化して、出力メモリに結果を書き出します。 + +出力メモリへの書き出しが完了したら、 +次の入力データに備えて、PCM Floatの半分のデータを切り捨て、PCM Cacheを空にして、1回分の信号処理は完了となります。 + +この処理をon_process()関数の中で実施します。 + +では、まずは必要なデータの定義を行います。 + +入力データはmemblk_t構造体にラップされた形で受け取ります。 +入力データのサイズは任意であるため、キューから取り出したメモリを一時的に保持しておく必要があります。 +そこで、struct my_worker_instance_s 構造体に、memblk_t *pcm_inメンバとして、ポインタで定義します。 +```c + memblk_t *pcm_in; +``` +また、図中のPCM Cache、PCM Floatも溜まったデータの量を管理するため、ローカルなmemblk_t構造体で管理します。 +そのために、更に2つのmemblk_tを今度は実態として定義します。 +```c + memblk_t pcm_cache; + memblk_t pcm_float; +``` + +FFTの計算には、ARM社製のCMSISを用います。WorkerではCMSISを利用することができるようになっています。 +CMSISのFFTにはその演算のためのインスタンスが必要になります。今回、32bit浮動小数点での演算を行うので、 +arm_rfft_fast_instance_f32型のインスタンスが必要になります。 +```c + arm_rfft_fast_instance_f32 rfft; +``` + +追加するメンバは以上となります。 +これらを構造体の中に記載していくと、struct my_worker_instance_sは、 +```c:struct my_worker_instance_s +struct my_worker_instance_s +{ + /* ALWORKERCOMMFW_INSTANCE should be on top of your instance */ + + ALWORKERCOMMFW_INSTANCE; + + /* Add specific items for your application here */ + + memblk_t *pcm_in; + + memblk_t pcm_cache; + memblk_t pcm_float; + + arm_rfft_fast_instance_f32 rfft; +}; +``` +となります。 + +続いてメモリインスタンスです。 +詳細なデータパスの図にあるように、 + +* 16bit整数でサイズがFFT_TAPSHALFのメモリ x 1 +* 32bit浮動小数点でサイズがFFT_TAPSのメモリ x 3 +* 32bit浮動小数点でサイズがFFT_TAPSHALFのメモリ x 1 + +の合計5枚のメモリとそれに加えて、窓関数用に、 + +* 32bit浮動小数点でサイズがFFT_TAPSのメモリ x 1 + +が必要になります。 +これらをstaticなメモリとして実態を記載します。 +> [!NOTE] +> my_worker_instanc_sにpcm_cache、pcm_floatをmemblk_t型で定義しましたが、memblk_tはあくまでメモリをラップする構造体のため、メモリそのものの実態は別に定義する必要があります。 + +```c +static short pcm_cache_mem[FFT_TAPSHALF]; +static float pcm_float_mem[FFT_TAPS]; + +static float fft_input[FFT_TAPS]; +static float fft_window[FFT_TAPS]; +static float fft_tmp[FFT_TAPS]; +static float fft_power[FFT_TAPSHALF]; +``` + +これをPrivate Dataのエリアに追記します。 + +```c +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct my_worker_instance_s g_instance; + +static short pcm_cache_mem[FFT_TAPSHALF]; +static float pcm_float_mem[FFT_TAPS]; + +static float fft_input[FFT_TAPS]; +static float fft_window[FFT_TAPS]; +static float fft_tmp[FFT_TAPS]; +static float fft_power[FFT_TAPSHALF]; +``` + +なお、テンプレート作成時に記載されている、以下の2行は今回は使用しないため削除してください。 + +```c +static memblk_t *imem_inuse = NULL; +static memblk_t *omem_inuse = NULL; +``` + +信号処理の実装を始める上で、2つの関数を追加します。 +* void init_hanningw(float *dat, int len) +* void calc_fft(struct my_worker_instance_s *inst, memblk_t *out + +まずは、init_hanningw()関数です。 +この関数は、lenで指定されたサイズのfloat配列に対してhanning窓を計算します。 + +```c +static void init_hanningw(float *dat, int len) +{ + int i; + float weight; + + for (i = 0; i < len / 2; i++) + { + weight = 0.5f * + (1.0f - arm_cos_f32(2 * PI * (float)i / len)); + dat[i] = weight; + dat[len - (i + 1)] = weight; + } +} +``` + +続いて、calc_fft()関数です。 +この関数は、pcm_floatを入力として、窓関数を掛け、FFTを行い、Powerスペクトルの算出と最大値による正規化を行い、 +outで指定されたmemblk_tに8bit 整数値としてその結果を書き出します。 +演算のほとんどはCMSISの関数になります。詳しくは [ARM CMSIS](https://arm-software.github.io/CMSIS_6/latest/General/index.html) のリファレンスマニュアルを参照してください。 + +```c +static void calc_fft(struct my_worker_instance_s *inst, memblk_t *out) +{ + uint32_t i; + float max; + float *pcm = (float *)memblk_dataptr(&inst->pcm_float); + + /* Calculate FFT with log */ + + arm_mult_f32(pcm, fft_window, fft_input, FFT_TAPS); + arm_rfft_fast_f32(&inst->rfft, fft_input, fft_tmp, 0); + arm_cmplx_mag_f32(fft_tmp, fft_power, FFT_TAPSHALF); + + /* Normalize */ + + arm_max_f32(fft_power, FFT_TAPSHALF, &max, &i); + arm_scale_f32(fft_power, 255.f/max, fft_power, FFT_TAPSHALF); + + /* Store result */ + + memblk_reset(out); + for (i = 0; i < FFT_TAPSHALF && !memblk_is_full(out); i++) + { + memblk_push_uint8(out, (uint8_t)fft_power[i]); + } +} +``` + +calc_fft()関数は、詳細図の黄色で示したメモリブロックを使った信号処理をすべて行っていることになります。 + +このファイルの編集も残りは、on_process()関数とmain()関数のみになります。 + +on_process()関数では、入出力のメモリブロックの管理と、pcm_cacheへのデータの詰め込み、 +pcm_floatへの変換と、calc_fft()を呼び出しての信号処理を行います。 + +最初にテンプレートで出力されたon_process()関数の中身を削除します。 +変数へのキャストのみ残し、一旦以下のようにします。 + +```c +static int on_process(void *arg) +{ + struct my_worker_instance_s *inst = + (struct my_worker_instance_s *)arg; + + return AL_COMMFW_RET_OK; +} +``` + +入力メモリはpcm_inメンバ変数で保持・管理しますが、出力メモリはこの関数内でのみテンポラリで管理します。 +そこで、ローカル変数として、以下の変数を定義します。 + +```c + memblk_t *fft_out; +``` + +まずは入力メモリブロックを入力メモリキューから取得して、pcm_cacheにデータがいっぱいになるまで入力メモリブロックからデータをコピーします。 +入力メモリブロックが空になったらその時点でメモリをComponentに返します。 + +入力メモリキューからメモリブロックを取得するには、```TAKE_IMEM()``` を用います。 +pcm_cacheにデータが満タンになっていない状況で入力メモリキューにメモリブロックがなければ、 +一旦、 return AL_COMMFW_RET_OK; としてon_process()関数から抜け、Componentからのメッセージ処理を行うようにします。 +> [!NOTE] +> on_process()関数は、main()関数の最後で呼び出しているalworker_commfw_msgloop()関数の中から呼び出されている関数で、 +> このalworker_commfw_msgloop()関数内で、Componentからのメッセージ処理も行っています。 +> そのため、適宜on_process()関数から抜けていかないと、Componentからのメッセージ処理が出来ず、デッドロックやMICなどのDMAのOverflowを引き起こす場合があります。 + +Componentからのメモリブロックを受け取ったら、memblk_single16()関数を使って、pcm_inからpcm_cacheに1ch分のメモリをコピー出来るだけコピーします。 +その後、pcm_inに入っているデータをすべて使い切ったかをチェックし、使い切っていたらメモリブロックをComponentに返却します。 +Componentへ返却するのは、FREE_MEMBLK()を使います。 + +全体をwhile(!memblk_is_full(&inst->pcm_cache))でくくることで、pcm_cacheが満タンになるまでこの状況を繰り返します。 + +```c + while(!memblk_is_full(&inst->pcm_cache)) + { + if (inst->pcm_in == NULL) + { + inst->pcm_in = TAKE_IMEM(inst); + if (inst->pcm_in == NULL) + { + return AL_COMMFW_RET_OK; /* Wait for PCM data */ + } + } + + memblk_single16(&inst->pcm_cache, inst->pcm_in); + if (memblk_is_empty(inst->pcm_in)) + { + FREE_MEMBLK(inst->pcm_in, inst); + inst->pcm_in = NULL; + } + } +``` + +pcm_cacheが満タンになると、このwhile()節の下の処理が進みます。 +16bit 1ch、FFT_TAPSHALFサイズ分のデータがpcm_cacheに溜まったので、FFTの演算を行って行きます。 +まず、出力するメモリブロックをキューから取得します。出力メモリブロックの取得は、TAKE_OMEM()を使います。 +出力メモリブロックが無い場合、入力メモリブロック同様、```return AL_COMMFW_RET_OK;```としてon_process()関数から抜けます。 +この状態では、pcm_cacheは満タンのままになるので、次にon_process()が呼ばれた場合であっても、前段のwhile()文は条件不一致で処理されず、 +出力メモリブロックの取得の部分から処理が再開します。 +出力メモリブロックが確保出来たら、```memblk_shift_drop()```関数でpcm_floatの古いデータ半分を捨て、```memblk_conv_pcm16tofloat()```関数でpcm_cacheのデータをfloatに変換しながらpcm_floatにコピーします。 +pcm_floatへのコピーが完了したら、先程作成した```calc_fft()```関数を呼び出し、パワースペクトルを計算し、結果をfft_outメモリブロックに格納します。 +結果の格納が終わったfft_outをFREE_MEMBLK()を用いてComponentに返却し、次の演算に備えてpcm_cacheを空にして、on_process()関数は終了となります。 + +```c + fft_out = TAKE_OMEM(inst); + if (fft_out == NULL) + { + return AL_COMMFW_RET_OK; /* Wait for memory to output */ + } + + memblk_shift_drop(&inst->pcm_float, sizeof(float) * FFT_TAPSHALF); + memblk_conv_pcm16tofloat(&inst->pcm_float, &inst->pcm_cache); + calc_fft(inst, fft_out); + + FREE_MEMBLK(fft_out, inst); + memblk_reset(&inst->pcm_cache); +``` + +これでon_process()関数の編集は完了です。上記の通り変更を加えた結果のon_process()関数は以下のようになります。 + +```c +static int on_process(void *arg) +{ + memblk_t *fft_out; + struct my_worker_instance_s *inst = + (struct my_worker_instance_s *)arg; + + while(!memblk_is_full(&inst->pcm_cache)) + { + if (inst->pcm_in == NULL) + { + inst->pcm_in = TAKE_IMEM(inst); + if (inst->pcm_in == NULL) + { + return AL_COMMFW_RET_OK; /* Wait for PCM data */ + } + } + + memblk_single16(&inst->pcm_cache, inst->pcm_in); + if (memblk_is_empty(inst->pcm_in)) + { + FREE_MEMBLK(inst->pcm_in, inst); + inst->pcm_in = NULL; + } + } + + fft_out = TAKE_OMEM(inst); + if (fft_out == NULL) + { + return AL_COMMFW_RET_OK; /* Wait for memory to output */ + } + + memblk_shift_drop(&inst->pcm_float, sizeof(float) * FFT_TAPSHALF); + memblk_conv_pcm16tofloat(&inst->pcm_float, &inst->pcm_cache); + calc_fft(inst, fft_out); + + FREE_MEMBLK(fft_out, inst); + memblk_reset(&inst->pcm_cache); + + return AL_COMMFW_RET_OK; +} +``` + +最後にmain()関数の編集になります。 +ここでは、my_worker_instance_s構造体のメンバの初期化を行います。 +以下のフレームワークに関連した構造体メンバの初期化の後ろに、今回追加したpcm_in, pcm_cache, pcm_float, rfftメンバの初期化と、 +hanning窓の初期化を行います。 + +```c + if (alworker_commfw_initialize((alworker_insthead_t *)&g_instance) != OK) + { + return 0; + } +``` + +上記の後ろに各メンバの初期化を追記します。 + +```c + if (alworker_commfw_initialize((alworker_insthead_t *)&g_instance) != OK) + { + return 0; + } + + g_instance.pcm_in = NULL; + + memblk_init(&g_instance.pcm_cache, (char *)pcm_cache_mem, sizeof(pcm_cache_mem)); + memblk_init(&g_instance.pcm_float, (char *)pcm_float_mem, sizeof(pcm_float_mem)); + arm_rfft_fast_init_f32(&g_instance.rfft, FFT_TAPS); + init_hanningw(fft_window, FFT_TAPS); +``` + +以上でmain()関数の変更は終了です。 +変更後のmain()関数は以下のようになります。 + +```c +int main(void) +{ + alcommfw_cbs_t *cbs = alworker_commfw_get_cbtable(); + + if (alworker_commfw_initialize((alworker_insthead_t *)&g_instance) != OK) + { + return 0; + } + + g_instance.pcm_in = NULL; + + memblk_init(&g_instance.pcm_cache, (char *)pcm_cache_mem, sizeof(pcm_cache_mem)); + memblk_init(&g_instance.pcm_float, (char *)pcm_float_mem, sizeof(pcm_float_mem)); + arm_rfft_fast_init_f32(&g_instance.rfft, FFT_TAPS); + init_hanningw(fft_window, FFT_TAPS); + + SET_PROCESS(cbs, on_process); + + alworker_send_bootmsg(FFT_WORKER_VERSION, NULL); + + alworker_commfw_msgloop((alworker_insthead_t *)&g_instance); + + return 0; +} +``` + +以上でfft/fft_worker_main.cの編集はすべて完了となります。 + +#### alusr_fft.cxxの編集 + +Worker側の実装が完了したので、残りはComponentの編集とComponentをマイクと接続し、 +マイク入力をFFT解析するコマンド(アプリ)を実装します。 + +まずは、alusr_fftクラスの実装ファイルの編集です。 +このファイルでは、alusr_fftクラスのコンストラクタが実装されており、 +その中で、固定長メモリプールを定義しています。 +このメモリプールのメモリブロックは、FFTの出力用メモリブロックとなります。 +今回、FFTの結果は、8bit 整数で、FFT_TAPSHALFサイズになります。 +そこで、個々のブロックサイズをこのサイズにします。 +具体的には、コンストラクタの中で呼び出している、_outmempool->create_instance()の第1引数を4096から変更します。 + +```c +alusr_fft::alusr_fft() : + audiolite_workercomp("fft", 8, 8), _outmempool(NULL) +{ + set_msglistener(&_msglsnr); + _outmempool = new audiolite_mempoolapbuf; + _outmempool->create_instance(FFT_TAPSHALF, 8); // <- ここを変更 + set_mempool(_outmempool); +} +``` + +以上でalusr_fft.cxxの編集は完了です。 + +#### alfft_main.cxxの編集 + +最後に作成したalusr_fftコンポーネントとMICコンポーネントを組み合わせて、 +マイク音声をFFTして周波数をUARTに出力するようにします。 + +テンプレートとして生成された中身は、何も記載のないmain()関数が定義されているのみです。 + +```c +#include +#include + +extern "C" int main(int argc, FAR char *argv[]) +{ + return 0; +} +``` + +MIC入力は、audiolite_inputcomp、FFT処理は先程作成したalusr_fftを用いますが、結果の出力先が無い状態です。 +そこで、データを受け取るとそのデータを表示するComponentを実装します。 + +audioliteの各クラスを利用するには、audiolite/audiolite.hをインクルードする必要があります。 +また、今回作成したalusr_fftクラスを利用するため、alusr_fft.hも併せてインクルードします。 + +```c +#include +#include + +#include +#include "alusr_fft.h" +``` + +続いて、結果の表示用のコンポーネントを実装します。 +AudioLiteのコンポーネントを作成するには、audiolite_componentクラスを継承したクラスを定義します。 +このクラスにon_data()メソッドをオーバーライドして実装すれば、bind()によって接続されたクラスからの出力データを受け取り処理することが出来ます。 +クラス名はfft_showとします。 + +```c++ +class fft_show : public audiolite_component +{ + public: + void on_data() + { + }; +}; +``` + +on_data()の中で入力されたデータをpop_data()メソッドを使って取得し、 +取得したメモリからデータを読み出すことで、FFTされたパワースペクトルデータを出力させることが出来ます。 +今回、各周波数成分の強度(0 ~ 255)を、アスキー文字でデータ16段階で表示するようにします。 +数値を16段階のアスキー文字に変換するメンバ関数gray_to_ascii()をfft_showクラスに追加し、on_data()で利用するようにします。 + +```c +class fft_show : public audiolite_component +{ + public: + char gray_to_ascii(unsigned char d) + { + if (d < 0x10) return ' '; + if (d < 0x20) return '.'; + if (d < 0x30) return ','; + if (d < 0x40) return '_'; + if (d < 0x50) return '-'; + if (d < 0x60) return '~'; + if (d < 0x70) return '+'; + if (d < 0x80) return 'i'; + if (d < 0x90) return 'b'; + if (d < 0xa0) return 'p'; + if (d < 0xb0) return 'A'; + if (d < 0xc0) return 'H'; + if (d < 0xd0) return 'V'; + if (d < 0xe0) return 'O'; + return 'Z'; + }; + + void on_data() + { + audiolite_memapbuf *mem = (audiolite_memapbuf *)pop_data(); + + if (mem) + { + uint8_t *data = (uint8_t *)mem->get_data(); + + for (int i = 0; i < 50; i++) + { + printf("%c", gray_to_ascii(*data++)); + } + + printf("\n"); + mem->release(); + } + }; +}; +``` + +以上でFFTの出力結果を表示するfft_showクラスの実装は完了となります。 +(メンバ関数の実装はクラス定義の外で行うのがC++言語の通例ですが、今回JAVA言語のようにクラスのメソッド定義の中で実装も記載しています。) + +なお、FFTのデータはFFT_TAPSHALF分ありますが、出力しているのは最初の50個のみとしています。(on_data()のfor文のループ回数) +これは、あまりデータ量が多いとUARTの出力にかかる時間が48KHzのサンプルに対して間に合わなくなってしまい、UART出力処理がボトルネックとなり、結果としてMIC入力のオーバーフローを招くことを避けるためです。 + +さて、後はmain()関数で各コンポーネントをつなぎ合わせてAudio処理を開始すればSpresenseのマイク入力の音声の周波数分析結果をUARTで確認することが出来ます。 + +audiolite_throughサンプルにもありますが、audiolite_inputcomはマイク入力データを入れるメモリプールが必要になります。 +今回、pcm_cacheがFFT_TAPSHALFサイズなので、FFT_TAPHALFサンプル数分(2ch/16bit)を保持出来るメモリサイズのメモリプールを作成してaudiolite_inputcompに取り付けます。 +また、コンポーネントからのイベントを取得するためのイベントリスナーには、標準のaudiolite_simplelistenerを使います。 +周波数の分析は15秒間行い、15秒経つとコマンドが終了するようにしています。 +これらを条件にmain()関数を実装すると以下のようになります。 + +```c +extern "C" int main(int argc, FAR char *argv[]) +{ + audiolite_simplelistener lsn; + audiolite_mempoolapbuf *membool = new audiolite_mempoolapbuf; + audiolite_inputcomp *aindev = new audiolite_inputcomp; + alusr_fft *fft = new alusr_fft; + fft_show *show = new fft_show; + + audiolite_set_evtlistener(&lsn); + audiolite_set_systemparam(48000, 16, 2); + membool->create_instance(FFT_TAPS * 2 * 2, 16); + aindev->set_mempool(membool); + + aindev->bind(fft)->bind(show); + aindev->start(); + + for(int i = 0; i < 15; i++) sleep(1); + + printf("Stop audio\n"); + aindev->stop(); + + aindev->unbindall(); + audiolite_eventdestroy(); + + delete show; + delete fft; + delete aindev; + delete membool; + + return 0; +} +``` + +これでalfft_main.cxxの編集は完了となり、すべての編集が完了しました。 +編集結果のalfft_main.cxxは以下のようになります。 + +```c +#include +#include + +#include +#include "alusr_fft.h" + +class fft_show : public audiolite_component +{ + public: + char gray_to_ascii(unsigned char d) + { + if (d < 0x10) return ' '; + if (d < 0x20) return '.'; + if (d < 0x30) return ','; + if (d < 0x40) return '_'; + if (d < 0x50) return '-'; + if (d < 0x60) return '~'; + if (d < 0x70) return '+'; + if (d < 0x80) return 'i'; + if (d < 0x90) return 'b'; + if (d < 0xa0) return 'p'; + if (d < 0xb0) return 'A'; + if (d < 0xc0) return 'H'; + if (d < 0xd0) return 'V'; + if (d < 0xe0) return 'O'; + return 'Z'; + }; + + void on_data() + { + audiolite_memapbuf *mem = (audiolite_memapbuf *)pop_data(); + + if (mem) + { + uint8_t *data = (uint8_t *)mem->get_data(); + + for (int i = 0; i < 50; i++) + { + printf("%c", gray_to_ascii(*data++)); + } + + printf("\n"); + mem->release(); + } + }; +}; + +extern "C" int main(int argc, FAR char *argv[]) +{ + int ret; + + audiolite_simplelistener lsn; + audiolite_mempoolapbuf *membool = new audiolite_mempoolapbuf; + audiolite_inputcomp *aindev = new audiolite_inputcomp; + alusr_fft *fft = new alusr_fft; + fft_show *show = new fft_show; + + audiolite_set_evtlistener(&lsn); + audiolite_set_systemparam(48000, 16, 2); + membool->create_instance(FFT_TAPS * 2 * 2, 16); + aindev->set_mempool(membool); + + aindev->bind(fft)->bind(show); + ret = aindev->start(); + + for(int i = 0; i < 15; i++) sleep(1); + + printf("Stop audio\n"); + aindev->stop(); + + aindev->unbindall(); + audiolite_eventdestroy(); + + delete show; + delete fft; + delete aindev; + delete membool; + + return 0; +} +``` + +### ビルド方法 + +ここでは組み上がったNuttShellコマンド:alfftのビルド方法を説明します。 +mkcmd.pyで生成したKconfigのファイルの内容説明で触れていますが、mkcmd.pyで生成したものはデフォルトでビルド対象となっています。 +後は、そのNuttShellコマンドが必要とするソフトウェアライブラリ・モジュールをコンフィグで有効にしてビルドを行えば作成したコマンドのビルドを行うことが出来ます。 + +#### Configuration + +まず、spresense/sdkディレクトリに移動して、make distcleanを実行します。 + +```shell +make distclean +``` + +その後、デフォルトコンフィグ feature/audioliteを有効にしてコンフィグを行います。 + +```shell +tools/config.py feature/audiolite +``` + +コンフィグは以上です。 + +#### ビルド、実機への焼き込みと実行 + +コンフィグが終わったら、その場でmakeを実行してビルドを行います。 + +```shell +make +``` + +無事にビルドが完了すると、 +spresense/sdk直下にnuttx.spkと、spresense/sdk/workerspksディレクトリに、fft.spkというファイルが生成されます。 +これらを実機にflash.shを使って焼き込みます。 +flash.shの使い方はSpresenseのドキュメントを参照してください。 + +```shell +tools/flash.sh -c /dev/ttyUSB0 nuttx.spk workerspks/fft.spk +``` + +無事実機へのインストールが完了したら、ターミナルソフトで実機に接続を行います。 +NuttShellのプロンプトが表示されたら、alfftと入力してEnterキーを押し実行すると、 +マイク入力の音声がFFTされて周波数成分がアスキー文字として出力されます。 +例えば、Spresenseに接続したマイクに聞こえるよう口笛を吹くなどしてみて音の高さに連動して表示が変わることを確認して見てください。 + +> {!NOTE] +> マイクはMIC-A入力を使います。Spresenseのハードウェアガイド [1.17.1 マイクチャネルの配置](https://developer.sony.com/spresense/development-guides/hw_docs_ja.html#_%E3%83%9E%E3%82%A4%E3%82%AF%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB%E3%81%AE%E9%85%8D%E7%BD%AE)を参考にマイクをAに接続してください。 + +```shell +nsh> alfft +``` + +実行結果 +```shell + ....,-AZZA-_,....... +,.........,__pZZA-,,,. +-_,... ...,_pZZA_,,,.... . +-_,.,. ....._pZZH-,,... +i~__,,,,,_--_iZZb.,,_,.. .. ...... . ... . + .,, .__,_-~bZZH,,,,,,,..... ... .. +... ..,,. ._~AZZH+,.,... .. ... . +,.. ... .,--iOZV+_,... ... . +..,___,,..._-bZZH_,_-__,..,,,.. .,. . .. +.,,,. ...,___+VZOb-,.... +ZVp~,... .,~AZZp~~_. .....,.. . ... +bi_.. .,,,-bZZV~.,........ +VA+_,... ..,-pZZH~_,,,,,,.. ...... ..... +pi_........,_bZZH~_,..,.. . +ZOb-_--, .,_._pHb- .... .. . ++~,... .,_+HZZA~-___,,,.............. +``` + +### 最後に + +このチュートリアルでは、mkalwcomp.pyコマンドを用いて生成されたworkerへのオフロード実装付きのAudioLiteのコンポーネントの実装方法を紹介しました。 +基本的には、生成されたWorker側のon_process()関数を実装することで様々な信号処理を実装することが出来るようになります。 +これを参考に、色々と試してみてください。 + +共有しても良い信号処理が出来たら、ぜひSpresenseへのコードのコントリビューションをお願いします。 + +### 補足技術解説 + +#### memblk_t + +memblk_tはアドレスとサイズで示されるメモリブロックを効率的に利用するための構造体です。 +[sdk/modules/audiolite/worker/common/alworker_memblk.h](https://github.com/SonySemiconductorSolutions/spresense/blob/new-master/sdk/modules/audiolite/worker/common/alworker_memblk.h)の中で以下のように定義されています。 + +```c +struct memblk_s +{ + sq_entry_t link; + char *addr; + int size; + int filled; + int used; + int eof; + int type; +}; +typedef struct memblk_s memblk_t; +``` + +それぞれのメンバ変数の意味は以下のようになります。 + +| メンバ変数名 | 型名 | 説明 | +| ------------ | ---------- | ---- | +| link | sq_entry_t | NuttXのシングルキューのエントリー。リスト構造を作るために利用 | +| addr | char * | 管理対象となるメモリの先頭アドレス | +| size | int | 管理対象メモリの全体サイズ | +| filled | int | 管理対象メモリに対して次のデータを書き込む際の書き込みポイントをオフセット値(Byte数)を示す。filled == sizeで満タンとなる。 | +| used | int | 管理対象メモリの中に溜まったデータのうち、どこまで利用したかを示すオフセット値(Byte数)を示す。size == filledで使い切りとなる。 | +| eof | int | AudioFrameとして最後のフレームであることを示す。 | +| type | int | メモリの所在を示す。入力メモリブロック、出力メモリブロック、ローカル(Worker内部の)メモリブロックを判別する。 | + +図で表すと以下のようになります。 + +![memblk_t](images/memblk_t.png) + + +メインコアのComponentからメモリを受け取るとフレームワーク内部でこのmemblk_t構造体が作成され、入力メモリキュー、もしくは出力メモリキューに入れられ、 +ユーザの信号処理を行う関数on_process()内などで、これらのキューからmemblk_tを取り出して利用することになります。 + +入力メモリキューからmemblk_tを取り出すにはTAKE_IMEM()を用い、 + +```c + memblk_t *mem = TAKE_IMEM(); +``` + +出力メモリキューから取り出すには、TAKE_OMEM()を利用します。 + +```c + memblk_t *mem = TAKE_OMEM(); +``` + +それぞれのメモリの開放(Componentへの返却・送信)は、入力メモリ・出力メモリどちらであってもFREE_MEMBLK()を用いて返却します。 + +memblk_tはWorker内部のメモリ管理にも用いることが出来ます。 +例えば、サイズ512Byteのchar 型のメモリがあった場合、memblk_init()を用いて以下のようなコードを書くことで、そのメモリをmemblk_tによって管理することが出来ます。 + +```c +char data[512]; +``` + +```c + memblk_t tmp_memblk; + memblk_init(&tmp_memblk, data, 512); +``` + +memblk_t構造体で管理されているメモリは、様々なユーティリティ関数を用いてメモリ内のデータを管理することが出来ます。 + +ここでは、このチュートリアルで利用しているユーティリティ関数について説明します。 + +##### memblk_dataptr(memblk_t *mem) + +このユーティリティ関数は、引数で与えられたメモリブロックのusedが示す場所のアドレスを返します。つまり、このメモリブロックで次に利用するメモリのポインタを渡します。データを配列として一度に利用したい場合などで利用します。 + +例:メモリに入っているデータをfloatとして利用する + +```c + float *pcm = (float *)memblk_dataptr(&mem); +``` + +##### memblk_reset(memblk_t *mem) + +このユーティリティ関数は、引数で与えられたメモリブロックの中身をすべて破棄して、空の状態にします。内部の動作は、filledメンバとusedメンバにそれぞれ0を入れます。こうすることで、結果としてメモリは何もデータが存在しない(filledが0)で、かつ利用済みデータが無い(usedが0)という状態になります。 + +```c + memblk_reset(&mem); +``` + +##### memblk_is_full(memblk_t *mem) + +このユーティリティ関数は、引数で与えられたメモリブロックのデータが満タンかどうかを判別し、満タンであればtrueを、そうでなければfalseを返します。 +満タンかどうかは、filled == sizeかどうかで判断しています。 + +例:満タンであればなにか処理を行う +```c + if (memblk_is_full(&mem)) + { + ... + } +``` + +##### memblk_is_empty(memblk_t *mem) + +このユーティリティ関数は、引数で与えられたメモリブロックの利用可能データが空(無い)かどうかを判別し、空であればtrueを、そうでなければfalseを返します。 +空かどうかは、used == filledかどうかで判断しています。 + +例:空であればなにか処理を行う +```c + if (memblk_is_empty(&mem)) + { + ... + } +``` + +##### memblk_push_uint8(memblk_t *mem, uint8_t data) + +このユーティリティ関数は、第1引数で与えられたメモリブロックに対して、第2引数で与えられたuint8_t型のデータを格納します。この関数によって、メモリブロックは1Byte分のデータが蓄えられ、filledメンバが1増えることになります。 + +例: +```c + uint8_t dat = 0x22; + memblk_push_uint8(&mem, dat); +``` + +##### memblk_single16(memblk_t *tgt, memblk_t *src) + +このユーティリティ関数は、第1引数のメモリブロックに対して、第2引数のメモリブロックからデータをコピーします。ただコピーするのではなく、srcが持つデータを2byteおきにコピーします。 + +これは、 +Audioデータが、16bitサンプル長のステレオデータとして入ってきた場合、信号処理を行う上で、一つのチャネルのデータのみを取り出したい、という場合に便利です。 + +ステレオデータの場合、LRLRLRLR..... と16ビットごとに交互に並んで入力されます。 +これを、 LLLLLL.... とLChのみ取得する、という場合にこの関数を用います。 + +例:mem_inに入っているステレオ16BitデータをLのみのmem_outにコピーする +```c + memblk_single16(&mem_out, &mem_in); +``` + +各メモリブロックでコピーされるサイズは、「コピー出来る最大数」コピーします。 +つまり、それぞれのメモリブロックのfilled, size, usedによる利用状況に応じて、コピー出来る最大のサンプル数をコピーし、更にコピーした結果に応じて、filled, size, usedを更新することで各メモリブロックの利用状況も更新されます。 + + +##### memblk_shift_drop(memblk_t *mem, int drop_sz) + +このユーティリティ関数は、第1引数で与えられたメモリブロックの中で未使用データを、管理しているメモリの先頭にシフトさせます。更に第2引数で示されたサイズのデータを捨てます。 + +動作イメージは以下の図のようになります。 + +![memblk_shift_drop()](images/memblk_shift_drop.png) + +残っているデータを保持しつつ、メモリを最大限使いたい場合や、次に来るデータのための空き容量を増やしたい場合などに利用します。 + +##### memblk_conv_pcm16tofloat(memblk_t *tgt, memblk_t *src); + +このユーティリティ関数は、第2引数で与えられたメモリブロックに保持されているデータを16ビット整数のデータとして、第1引数で与えられたメモリブロックにfloatに変換してコピーを行います。 + +16Bit整数で入ってきたオーディオデータを浮動小数点で処理したい場合などに用います。 + +使用例: +```c + memblk_conv_pcm16tofloat(&mem_float, &mem_pcm); +``` + +その他にも様々なユーティリティ関数があります。 +詳しくは、[ヘッダファイル](https://github.com/SonySemiconductorSolutions/spresense/blob/new-master/sdk/modules/audiolite/worker/common/alworker_memblk.h)を参照してみてください。 + +# English Section + +T.B.D. + diff --git a/examples/audiolite_fft/alusr_fftworker.cxx b/examples/audiolite_fft/alusr_fftworker.cxx new file mode 100644 index 000000000..daf085c85 --- /dev/null +++ b/examples/audiolite_fft/alusr_fftworker.cxx @@ -0,0 +1,45 @@ +#include +#include + +/**************************************************************************** + * alusr_fftworker Class Methods + ****************************************************************************/ + +alusr_fftworker::alusr_fftworker() : + audiolite_workercomp("fftworker", 8, 8), _outmempool(NULL) +{ + set_msglistener(&_msglsnr); + _outmempool = new audiolite_mempoolapbuf; + _outmempool->create_instance(FFT_TAPSHALF, 8); + set_mempool(_outmempool); +} + +alusr_fftworker::~alusr_fftworker() +{ + set_mempool(NULL); + if (_outmempool) + delete _outmempool; +} + +/**************************************************************************** + * Message Listener Class Methods + ****************************************************************************/ + +void alusr_fftworker::fftworker_msglistener::bootup( + audiolite_workercomp *wcomp, al_wtask_t *wtask, int version, void *d) +{ + // This method is called just after receiving boot-up + // message from the worker + + if (version == FFTWORKER_WORKER_VERSION) + { + alworker_send_systemparam(wtask, wcomp->channels(), + wcomp->samplingrate(), + wcomp->samplebitwidth()); + alworker_send_start(wtask); + } + else + { + wcomp->publish_event(AL_EVENT_WRONGVERSION, version); + } +} diff --git a/examples/audiolite_fft/alusr_fftworker.h b/examples/audiolite_fft/alusr_fftworker.h new file mode 100644 index 000000000..99b61b452 --- /dev/null +++ b/examples/audiolite_fft/alusr_fftworker.h @@ -0,0 +1,35 @@ +#ifndef __INCLUDE_AUDIOLITE_USER_FFTWORKER_H +#define __INCLUDE_AUDIOLITE_USER_FFTWORKER_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +/**************************************************************************** + * Class Definitions + ****************************************************************************/ + +class alusr_fftworker : public audiolite_workercomp +{ + protected: + class fftworker_msglistener : public audiolite_stdworker_msglistener + { + public: + virtual ~fftworker_msglistener(){}; + void bootup(audiolite_workercomp *wcomp, al_wtask_t *wtask, + int version, void *d); + }; + + fftworker_msglistener _msglsnr; + audiolite_mempoolapbuf *_outmempool; + + public: + alusr_fftworker(); + virtual ~alusr_fftworker(); +}; + +#endif /* __INCLUDE_AUDIOLITE_USER_FFTWORKER_H */ diff --git a/examples/audiolite_fft/audiolite_fft_main.cxx b/examples/audiolite_fft/audiolite_fft_main.cxx new file mode 100644 index 000000000..459426c43 --- /dev/null +++ b/examples/audiolite_fft/audiolite_fft_main.cxx @@ -0,0 +1,82 @@ + +#include +#include + +#include +#include "alusr_fftworker.h" + +#define MAX_DISP_LEN (50) + +class fft_disp : public audiolite_component +{ + public: + char gray_to_ascii(unsigned char d) + { + if (d < 0x10) return ' '; + if (d < 0x20) return '.'; + if (d < 0x30) return ','; + if (d < 0x40) return '_'; + if (d < 0x50) return '-'; + if (d < 0x60) return '~'; + if (d < 0x70) return '+'; + if (d < 0x80) return 'i'; + if (d < 0x90) return 'b'; + if (d < 0xa0) return 'p'; + if (d < 0xb0) return 'A'; + if (d < 0xc0) return 'H'; + if (d < 0xd0) return 'V'; + if (d < 0xe0) return 'O'; + return 'Z'; + }; + + void on_data() + { + audiolite_memapbuf *mem = (audiolite_memapbuf *)pop_data(); + + if (mem) + { + uint8_t *data = (uint8_t *)mem->get_data(); + + for (int i = 0; i < MAX_DISP_LEN; i++) + { + printf("%c", gray_to_ascii(*data++)); + } + + printf("\n"); + mem->release(); + } + }; +}; + +extern "C" int main(int argc, FAR char *argv[]) +{ + audiolite_simplelistener lsn; + audiolite_mempoolapbuf *membool = new audiolite_mempoolapbuf; + audiolite_inputcomp *aindev = new audiolite_inputcomp; + alusr_fftworker *fft = new alusr_fftworker; + fft_disp *disp = new fft_disp; + + audiolite_set_evtlistener(&lsn); + audiolite_set_systemparam(48000, 16, 2); + + membool->create_instance(FFT_TAPS * 2 * 2, 16); + aindev->set_mempool(membool); + + aindev->bind(fft)->bind(disp); + aindev->start(); + + for(int i = 0; i < 15; i++) sleep(1); + + printf("Stop audio\n"); + aindev->stop(); + + aindev->unbindall(); + audiolite_eventdestroy(); + + delete disp; + delete fft; + delete aindev; + delete membool; + + return 0; +} diff --git a/examples/audiolite_fft/fftworker/.gitignore b/examples/audiolite_fft/fftworker/.gitignore new file mode 100644 index 000000000..5e744b7f5 --- /dev/null +++ b/examples/audiolite_fft/fftworker/.gitignore @@ -0,0 +1,3 @@ +fftworker +*.elf +*.spk diff --git a/examples/audiolite_fft/fftworker/Makefile b/examples/audiolite_fft/fftworker/Makefile new file mode 100644 index 000000000..0225acf88 --- /dev/null +++ b/examples/audiolite_fft/fftworker/Makefile @@ -0,0 +1,24 @@ +include $(APPDIR)/Make.defs +-include $(SDKDIR)/Make.defs + +ALWORKER_COMMON = $(SDKDIR)/modules/audiolite/worker/common + +BUILD_EXECUTE = 1 + +# ALWORKER_USE_CMSIS = 1 +# ALWORKER_USE_RESAMPLER = 1 + +BIN = fftworker +SPK = $(BIN).spk + +CSRCS = fftworker_worker_main.c + +CFLAGS += +LDLIBPATH = +LDLIBS = + +VPASH_DIRS = + +INCDIRS = + +include $(ALWORKER_COMMON)/mkfiles/alworker.mk diff --git a/examples/audiolite_fft/fftworker/alworker_commfw_config.h b/examples/audiolite_fft/fftworker/alworker_commfw_config.h new file mode 100644 index 000000000..e17c123ef --- /dev/null +++ b/examples/audiolite_fft/fftworker/alworker_commfw_config.h @@ -0,0 +1,30 @@ +#ifndef __AUDIOLITE_WORKER_COMMON_ALWORKER_COMMFW_CONFIG_H +#define __AUDIOLITE_WORKER_COMMON_ALWORKER_COMMFW_CONFIG_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/** Definition of NOTUSE_XXXXXX + * + * If you want to handle messages below, + * comment out to enable it. + */ + +#define NOTUSE_STARTING +#define NOTUSE_STOPPING +#define NOTUSE_SYSPAUSE +#define NOTUSE_INSTGAIN +#define NOTUSE_ORGMSG +#define NOTUSE_SYSDBG + +/** Definition of Memory block QUEUE size + * + * Input side memory block size will defined as CONF_WORKER_IMEMMAX. + * Output side memory block size will defined as CONF_WORKER_OMEMMAX. + */ + +#define CONF_WORKER_IMEMMAX (8) +#define CONF_WORKER_OMEMMAX (8) + +#endif /* __AUDIOLITE_WORKER_COMMON_ALWORKER_COMMFW_CONFIG_H */ diff --git a/examples/audiolite_fft/fftworker/fftworker_worker_main.c b/examples/audiolite_fft/fftworker/fftworker_worker_main.c new file mode 100644 index 000000000..9fd3cca13 --- /dev/null +++ b/examples/audiolite_fft/fftworker/fftworker_worker_main.c @@ -0,0 +1,177 @@ +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include "fftworker_worker_main.h" + +#include "arm_math.h" + +/**************************************************************************** + * Private Data Types + ****************************************************************************/ + +struct my_worker_instance_s +{ + /* ALWORKERCOMMFW_INSTANCE should be on top of your instance */ + + ALWORKERCOMMFW_INSTANCE; + + /* Add specific items for your application here */ + + memblk_t *pcm_in; + + memblk_t pcm_cache; + memblk_t pcm_float; + + arm_rfft_fast_instance_f32 rfft; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct my_worker_instance_s g_instance; + +static short pcm_cache_mem[FFT_TAPSHALF]; +static float pcm_float_mem[FFT_TAPS]; + +static float fft_input[FFT_TAPS]; +static float fft_window[FFT_TAPS]; +static float fft_tmp[FFT_TAPS]; +static float fft_power[FFT_TAPSHALF]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void init_hanningw(float *dat, int len) +{ + int i; + float weight; + + for (i = 0; i < len / 2; i++) + { + weight = 0.5f * + (1.0f - arm_cos_f32(2 * PI * (float)i / len)); + dat[i] = weight; + dat[len - (i + 1)] = weight; + } +} + +static void calc_fft(struct my_worker_instance_s *inst, memblk_t *out) +{ + uint32_t i; + float max; + float *pcm = (float *)memblk_dataptr(&inst->pcm_float); + + /* Calculate FFT with log */ + + arm_mult_f32(pcm, fft_window, fft_input, FFT_TAPS); + arm_rfft_fast_f32(&inst->rfft, fft_input, fft_tmp, 0); + arm_cmplx_mag_f32(fft_tmp, fft_power, FFT_TAPSHALF); + + /* Normalize */ + + arm_max_f32(fft_power, FFT_TAPSHALF, &max, &i); + arm_scale_f32(fft_power, 255.f/max, fft_power, FFT_TAPSHALF); + + /* Store result */ + + memblk_reset(out); + for (i = 0; i < FFT_TAPSHALF && !memblk_is_full(out); i++) + { + memblk_push_uint8(out, (uint8_t)fft_power[i]); + } +} + +/* on_process(): + * This is called when the state is in PROCESS. + * + * Return code controls state change. + * AL_COMMFW_RET_OK : Stay the state to process next work. + * AL_COMMFW_RET_NOIMEM : Change to WAIT_IMEM for waiting next input. + * AL_COMMFW_RET_NOOMEM : Change to WAIT_OMEM for waiting next output. + */ + +static int on_process(void *arg) +{ + memblk_t *fft_out; + struct my_worker_instance_s *inst = + (struct my_worker_instance_s *)arg; + + while(!memblk_is_full(&inst->pcm_cache)) + { + if (inst->pcm_in == NULL) + { + inst->pcm_in = PEEK_IMEM(inst); + if (inst->pcm_in == NULL) + { + return AL_COMMFW_RET_OK; /* Wait for PCM data */ + } + } + + memblk_single16(&inst->pcm_cache, inst->pcm_in); + if (memblk_is_empty(inst->pcm_in)) + { + inst->pcm_in = TAKE_IMEM(inst); + FREE_MEMBLK(inst->pcm_in, inst); + inst->pcm_in = NULL; + } + } + + fft_out = TAKE_OMEM(inst); + if (fft_out == NULL) + { + return AL_COMMFW_RET_OK; /* Wait for memory to output */ + } + + memblk_shift_drop(&inst->pcm_float, sizeof(float) * FFT_TAPSHALF); + memblk_conv_pcm16tofloat(&inst->pcm_float, &inst->pcm_cache); + calc_fft(inst, fft_out); + + FREE_MEMBLK(fft_out, inst); + memblk_reset(&inst->pcm_cache); + + return AL_COMMFW_RET_OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(void) +{ + alcommfw_cbs_t *cbs = alworker_commfw_get_cbtable(); + + if (alworker_commfw_initialize((alworker_insthead_t *)&g_instance) != OK) + { + return 0; + } + + g_instance.pcm_in = NULL; + + memblk_init(&g_instance.pcm_cache, (char *)pcm_cache_mem, sizeof(pcm_cache_mem)); + memblk_init(&g_instance.pcm_float, (char *)pcm_float_mem, sizeof(pcm_float_mem)); + arm_rfft_fast_init_f32(&g_instance.rfft, FFT_TAPS); + init_hanningw(fft_window, FFT_TAPS); + + /* Set callbacks to handle host message and + * state processing + */ + + SET_PROCESS(cbs, on_process); + + /* Send boot message to host to notice this worker is ready */ + + alworker_send_bootmsg(FFTWORKER_WORKER_VERSION, NULL); + + /* Start message loop. + * This function returns receive SYSTERM message from a host. + */ + + alworker_commfw_msgloop((alworker_insthead_t *)&g_instance); + + return 0; +} diff --git a/examples/audiolite_fft/fftworker/fftworker_worker_main.h b/examples/audiolite_fft/fftworker/fftworker_worker_main.h new file mode 100644 index 000000000..7b2320181 --- /dev/null +++ b/examples/audiolite_fft/fftworker/fftworker_worker_main.h @@ -0,0 +1,11 @@ +#ifndef __AUDIOLITE_WORKER_USR_FFTWORKER_H +#define __AUDIOLITE_WORKER_USR_FFTWORKER_H + +/* Add a common definition between worker and the audiolite component here */ + +#define FFTWORKER_WORKER_VERSION (1) + +#define FFT_TAPS (512) +#define FFT_TAPSHALF (FFT_TAPS / 2) + +#endif /* __AUDIOLITE_WORKER_USR_FFTWORKER_H */ diff --git a/examples/audiolite_fft/images/component.png b/examples/audiolite_fft/images/component.png new file mode 100644 index 000000000..346b4670c Binary files /dev/null and b/examples/audiolite_fft/images/component.png differ diff --git a/examples/audiolite_fft/images/fft_component_detail.png b/examples/audiolite_fft/images/fft_component_detail.png new file mode 100644 index 000000000..f7304eb4c Binary files /dev/null and b/examples/audiolite_fft/images/fft_component_detail.png differ diff --git a/examples/audiolite_fft/images/fft_component_outline.png b/examples/audiolite_fft/images/fft_component_outline.png new file mode 100644 index 000000000..9ca72ce14 Binary files /dev/null and b/examples/audiolite_fft/images/fft_component_outline.png differ diff --git a/examples/audiolite_fft/images/memblk_shift_drop.png b/examples/audiolite_fft/images/memblk_shift_drop.png new file mode 100644 index 000000000..6058a96cf Binary files /dev/null and b/examples/audiolite_fft/images/memblk_shift_drop.png differ diff --git a/examples/audiolite_fft/images/memblk_t.png b/examples/audiolite_fft/images/memblk_t.png new file mode 100644 index 000000000..818f19d3e Binary files /dev/null and b/examples/audiolite_fft/images/memblk_t.png differ diff --git a/examples/audiolite_fft/images/worker_component.png b/examples/audiolite_fft/images/worker_component.png new file mode 100644 index 000000000..b66199520 Binary files /dev/null and b/examples/audiolite_fft/images/worker_component.png differ diff --git a/examples/audiolite_mp3player/audiolite_mp3player_main.cxx b/examples/audiolite_mp3player/audiolite_mp3player_main.cxx index 75e985211..356b50821 100644 --- a/examples/audiolite_mp3player/audiolite_mp3player_main.cxx +++ b/examples/audiolite_mp3player/audiolite_mp3player_main.cxx @@ -40,6 +40,8 @@ #include #include +#include +#include #include @@ -64,7 +66,7 @@ class my_mp3listener : public audiolite_eventlistener { printf("Event %s is happened : %d\n", convert_evtid(evt), (int)arg); - if (evt == AL_EVENT_DECODEDONE) + if (evt == AL_EVENT_STOPOUTPUT) { playing = false; } @@ -81,6 +83,7 @@ int main(int argc, FAR char *argv[]) int ret; my_mp3listener lsn; int volume = 1000; + struct pollfd pfd; /* Argument check */ @@ -191,7 +194,17 @@ int main(int argc, FAR char *argv[]) while (lsn.playing) { - usleep(10 * 1000); + pfd.fd = fileno(stdin); + pfd.events = POLLIN; + + poll(&pfd, 1, 10 /* ms */); + if (pfd.revents & POLLIN) + { + if (getchar() == 'q') + { + break; + } + } } /* Stop playing */ diff --git a/examples/audiolite_mp3player/event_str.h b/examples/audiolite_mp3player/event_str.h index 1ac30b748..c2fb5c1df 100644 --- a/examples/audiolite_mp3player/event_str.h +++ b/examples/audiolite_mp3player/event_str.h @@ -1,3 +1,45 @@ +/**************************************************************************** + * examples/audiolite_mp3player/event_str.h + * + * Copyright 2024 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __EXAMPLES_AUDIOLITE_MP3PLAYER_EVENT_STR_H +#define __EXAMPLES_AUDIOLITE_MP3PLAYER_EVENT_STR_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + #define STRINGCASE(e) case AL_EVENT_##e: return #e; static const char *convert_evtid(int id) @@ -26,11 +68,13 @@ static const char *convert_evtid(int id) STRINGCASE(SENDERROR) STRINGCASE(MP3FRAMEINFO) STRINGCASE(MP3DECWORKEREND) - STRINGCASE(MP3DECUNKNOWNEVT) + STRINGCASE(UNKNOWN) STRINGCASE(MP3DECERROR) STRINGCASE(MP3DEC_WRONGTYPE) - STRINGCASE(MP3DEC_WRONGVER) + STRINGCASE(WRONGVERSION) default: return "not event id..."; } } + +#endif /* __EXAMPLES_AUDIOLITE_MP3PLAYER_EVENT_STR_H */ diff --git a/examples/audiolite_rec2net/event_str.h b/examples/audiolite_rec2net/event_str.h index 893531564..378208c76 100644 --- a/examples/audiolite_rec2net/event_str.h +++ b/examples/audiolite_rec2net/event_str.h @@ -72,8 +72,10 @@ static const char *convert_evtid(int id) STRINGCASE(SENDERROR) STRINGCASE(MP3FRAMEINFO) STRINGCASE(MP3DECWORKEREND) - STRINGCASE(MP3DECUNKNOWNEVT) + STRINGCASE(UNKNOWN) STRINGCASE(MP3DECERROR) + STRINGCASE(MP3DEC_WRONGTYPE) + STRINGCASE(WRONGVERSION) default: return "not event id..."; } diff --git a/examples/audiolite_through/my_display_data.h b/examples/audiolite_through/my_display_data.h index 664030b38..11ed946a5 100644 --- a/examples/audiolite_through/my_display_data.h +++ b/examples/audiolite_through/my_display_data.h @@ -79,7 +79,7 @@ class my_display_data : public audiolite_component /* Pass the data to later block. */ - push_data(0, mem); + push_data(mem); /* Release the memory it after finishing use */ diff --git a/examples/audiolite_wavplayer/event_str.h b/examples/audiolite_wavplayer/event_str.h index 42cb3b2a6..fe08b38f9 100644 --- a/examples/audiolite_wavplayer/event_str.h +++ b/examples/audiolite_wavplayer/event_str.h @@ -1,5 +1,51 @@ +/**************************************************************************** + * examples/audiolite_wavplayer/event_str.h + * + * Copyright 2024 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __EXAMPLES_AUDIOLITE_WAVPLAYER_EVENT_STR_H +#define __EXAMPLES_AUDIOLITE_WAVPLAYER_EVENT_STR_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + #define STRINGCASE(e) case AL_EVENT_##e: return #e; +/**************************************************************************** + * Private Functions + ****************************************************************************/ + static const char *convert_evtid(int id) { switch (id) @@ -26,9 +72,13 @@ static const char *convert_evtid(int id) STRINGCASE(SENDERROR) STRINGCASE(MP3FRAMEINFO) STRINGCASE(MP3DECWORKEREND) - STRINGCASE(MP3DECUNKNOWNEVT) + STRINGCASE(UNKNOWN) STRINGCASE(MP3DECERROR) + STRINGCASE(MP3DEC_WRONGTYPE) + STRINGCASE(WRONGVERSION) default: return "not event id..."; } } + +#endif /* __EXAMPLES_AUDIOLITE_WAVPLAYER_EVENT_STR_H */ diff --git a/examples/audiolite_wavrecorder/event_str.h b/examples/audiolite_wavrecorder/event_str.h index 42cb3b2a6..b69729f07 100644 --- a/examples/audiolite_wavrecorder/event_str.h +++ b/examples/audiolite_wavrecorder/event_str.h @@ -1,5 +1,51 @@ +/**************************************************************************** + * examples/audiolite_wavrecorder/event_str.h + * + * Copyright 2024 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __EXAMPLES_AUDIOLITE_WAVRECORDER_EVENT_STR_H +#define __EXAMPLES_AUDIOLITE_WAVRECORDER_EVENT_STR_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + #define STRINGCASE(e) case AL_EVENT_##e: return #e; +/**************************************************************************** + * Private Functions + ****************************************************************************/ + static const char *convert_evtid(int id) { switch (id) @@ -26,9 +72,13 @@ static const char *convert_evtid(int id) STRINGCASE(SENDERROR) STRINGCASE(MP3FRAMEINFO) STRINGCASE(MP3DECWORKEREND) - STRINGCASE(MP3DECUNKNOWNEVT) + STRINGCASE(UNKNOWN) STRINGCASE(MP3DECERROR) + STRINGCASE(MP3DEC_WRONGTYPE) + STRINGCASE(WRONGVERSION) default: return "not event id..."; } } + +#endif /* __EXAMPLES_AUDIOLITE_WAVRECORDER_EVENT_STR_H */ diff --git a/examples/awsiot_gnsslogger/awsiot_gnsslogger_main.c b/examples/awsiot_gnsslogger/awsiot_gnsslogger_main.c index 98f21a0e7..cbec1be5a 100644 --- a/examples/awsiot_gnsslogger/awsiot_gnsslogger_main.c +++ b/examples/awsiot_gnsslogger/awsiot_gnsslogger_main.c @@ -87,6 +87,7 @@ static void set_system_time(uint16_t year, uint8_t month, uint8_t day, struct tm tm; struct timespec ts; + memset(&tm, 0, sizeof(tm)); tm.tm_sec = 0; /* Seconds (0-61, allows for leap seconds) */ tm.tm_min = minute; /* Minutes (0-59) */ tm.tm_hour = hour; /* Hours (0-23) */ diff --git a/examples/ble_mouse_central/Kconfig b/examples/ble_mouse_central/Kconfig new file mode 100644 index 000000000..ba23b37fa --- /dev/null +++ b/examples/ble_mouse_central/Kconfig @@ -0,0 +1,62 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config EXAMPLES_BLE_MOUSE_CENTRAL + tristate "BLE Mouse Central example" + default n + ---help--- + Enable the ble_mouse_central app + +if EXAMPLES_BLE_MOUSE_CENTRAL + +config EXAMPLES_BLE_MOUSE_CENTRAL_PROGNAME + string "Program name" + default "ble_mouse_central" + ---help--- + This is the name of the program that will be use when the NSH ELF + program is installed. + +config EXAMPLES_BLE_MOUSE_CENTRAL_PRIORITY + int "ble_mouse_central task priority" + default 100 + +config EXAMPLES_BLE_MOUSE_CENTRAL_STACKSIZE + int "ble_mouse_central stack size" + default DEFAULT_TASK_STACKSIZE + +config EXAMPLES_BLE_MOUSE_INPUT_DEVICE + bool "Enable BLE mouse input device" + select INPUT + select INPUT_MOUSE + default n + ---help--- + Use BLE mouse as an input device. + +if EXAMPLES_BLE_MOUSE_INPUT_DEVICE + +config EXAMPLES_BLE_MOUSE_INPUT_DEVPATH + string "BLE mouse device path" + default "/dev/mouse0" + ---help--- + The path to the BLE mouse device. Default: "/dev/mouse0" + +config EXAMPLES_BLE_MOUSE_READER_PROGNAME + string "Program name" + default "mouse_reader" + ---help--- + This is the name of the program that will be use when the NSH ELF + program is installed. + +config EXAMPLES_BLE_MOUSE_READER_PRIORITY + int "mouse_reader task priority" + default 100 + +config EXAMPLES_BLE_MOUSE_READER_STACKSIZE + int "mouse_reader stack size" + default DEFAULT_TASK_STACKSIZE + +endif # EXAMPLES_BLE_MOUSE_INPUT_DEVICE + +endif # EXAMPLES_BLE_MOUSE_CENTRAL diff --git a/examples/ble_mouse_central/Make.defs b/examples/ble_mouse_central/Make.defs new file mode 100644 index 000000000..e8c59babb --- /dev/null +++ b/examples/ble_mouse_central/Make.defs @@ -0,0 +1,38 @@ +############################################################################ +# examples/ble_mouse_central/Make.defs +# +# Copyright 2024 Sony Semiconductor Solutions Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name of Sony Semiconductor Solutions Corporation nor +# the names of its contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +ifneq ($(CONFIG_EXAMPLES_BLE_MOUSE_CENTRAL),) +CONFIGURED_APPS += ble_mouse_central +endif diff --git a/sdk/tools/extlib.mk b/examples/ble_mouse_central/Makefile similarity index 62% rename from sdk/tools/extlib.mk rename to examples/ble_mouse_central/Makefile index 37299fbf0..fac96588c 100644 --- a/sdk/tools/extlib.mk +++ b/examples/ble_mouse_central/Makefile @@ -1,7 +1,7 @@ ############################################################################ -# bsp/scripts/extlib.mk +# examples/ble_mouse_central/Makefile # -# Copyright 2018 Sony Semiconductor Solutions Corporation +# Copyright 2024 Sony Semiconductor Solutions Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -33,35 +33,26 @@ # ############################################################################ -ifeq ($(CONFIG_RIL),y) - ifeq ($(WINTOOL),y) - RILLIB = "${shell cygpath -w $(TOPDIR)$(DELIM)$(CONFIG_APPS_DIR)$(DELIM)ril}" - else - RILLIB = "$(TOPDIR)$(DELIM)$(CONFIG_APPS_DIR)$(DELIM)ril" - endif - LIBPATHS += -L $(RILLIB) - EXTRA_LIBS += -lril -endif +include $(APPDIR)/Make.defs +-include $(SDKDIR)/Make.defs -ifeq ($(CONFIG_EINK_ET014TT1),y) - ifeq ($(WINTOOL),y) - EINKLIB = "${shell cygpath -w $(TOPDIR)$(DELIM)$(CONFIG_APPS_DIR)$(DELIM)swtcon}" - else - EINKLIB = "$(TOPDIR)$(DELIM)$(CONFIG_APPS_DIR)$(DELIM)swtcon" - endif - LIBPATHS += -L $(EINKLIB) - EXTRA_LIBS += -lSWTCON2_Cortex-M4_wchar32 -endif +PROGNAME = $(CONFIG_EXAMPLES_BLE_MOUSE_CENTRAL_PROGNAME) +PRIORITY = $(CONFIG_EXAMPLES_BLE_MOUSE_CENTRAL_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_BLE_MOUSE_CENTRAL_STACKSIZE) +MODULE = $(CONFIG_EXAMPLES_BLE_MOUSE_CENTRAL) + +CSRCS = ble_central_app.c +MAINSRC = ble_mouse_central_main.c + +ifeq ($(CONFIG_EXAMPLES_BLE_MOUSE_INPUT_DEVICE),y) + +PROGNAME += $(CONFIG_EXAMPLES_BLE_MOUSE_READER_PROGNAME) +PRIORITY += $(CONFIG_EXAMPLES_BLE_MOUSE_READER_PRIORITY) +STACKSIZE += $(CONFIG_EXAMPLES_BLE_MOUSE_READER_STACKSIZE) +MODULE += $(CONFIG_EXAMPLES_BLE_MOUSE_READER) + +MAINSRC += mouse_reader_main.c -ifeq ($(CONFIG_GPSUTILS_CXD56NMEA_LIB),y) - ifeq ($(APPDIR),) - APPDIR := $(TOPDIR)$(DELIM)$(CONFIG_APPS_DIR) - endif - ifeq ($(WINTOOL),y) - CXD56NMEALIBPATH = "${shell cygpath -w $(APPDIR)$(DELIM)gpsutils$(DELIM)cxd56nmea}" - else - CXD56NMEALIBPATH = "$(APPDIR)$(DELIM)gpsutils$(DELIM)cxd56nmea" - endif - LIBPATHS += -L $(CXD56NMEALIBPATH) - EXTRA_LIBS += -lcxd56nmea endif + +include $(APPDIR)/Application.mk diff --git a/examples/ble_mouse_central/ble_central_app.c b/examples/ble_mouse_central/ble_central_app.c new file mode 100644 index 000000000..d33c5119e --- /dev/null +++ b/examples/ble_mouse_central/ble_central_app.c @@ -0,0 +1,793 @@ +/**************************************************************************** + * examples/ble_mouse_central/ble_central_app.c + * + * Copyright 2024 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ble_central_app.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define BLE_APP_BUFFER_LEN 64 +#define BLE_APP_DEVNAME_LEN 32 + +#define BLE_APP_DEFAULT_MTU_SIZE 23 + +/* Maximum number of handles with the same UUID */ + +#define MAX_HANDLES_OF_UUID 8 + +/* Print the detail log (1:enable, 0:disable) */ + +#define LOG_SCAN 1 +#define LOG_DISCOVERY 1 +#define LOG_NOTIFY 0 +#define LOG_READ 0 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct handle_set_s +{ + uint16_t handle; + uint16_t cccd_handle; +}; + +/* Discovery list node */ +struct discover_node_s +{ + discover_cb_t cb; + BLE_UUID uuid; + int nhandle; + struct handle_set_s handles[MAX_HANDLES_OF_UUID]; + SLIST_ENTRY(discover_node_s) entries; +}; + +/* Notify list node */ + +struct notify_node_s +{ + notify_cb_t cb; + BLE_UUID uuid; + int nhandle; + struct handle_set_s handles[MAX_HANDLES_OF_UUID]; + SLIST_ENTRY(notify_node_s) entries; +}; + +/* Private structure for BLE central app */ + +struct ble_app_private_t +{ + enum ble_app_event event; + sem_t event_sync; + int result; + uint8_t buffer[BLE_APP_BUFFER_LEN]; + int len; + sem_t api_sync; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void on_scan(BT_ADDR addr, uint8_t *data, uint8_t len); +static void on_state_change(struct ble_state_s *state, bool connected, uint8_t cause); +static void on_mtusize(uint16_t handle, uint16_t sz); +static void on_discovered(struct ble_gatt_event_db_discovery_t *db_disc); +static void on_enc_result(uint16_t handle, bool result); +static void on_devicename(const char *name); + +static void on_write(uint16_t conn_handle, struct ble_gatt_char_s *gatt_char); +static void on_read(uint16_t conn_handle, struct ble_gatt_char_s *gatt_char); +static void on_notify(uint16_t conn_handle, struct ble_gatt_char_s *gatt_char); +static void on_desc_write(uint16_t connhdl, uint16_t charhdl, int result); +static void on_desc_read(uint16_t connhdl, uint16_t charhdl, uint8_t *data, uint16_t len); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct ble_common_ops_s ble_common_ops = + { + .scan_result = on_scan, + .mtusize = on_mtusize, + .connect_status_changed = on_state_change, + .encryption_result = on_enc_result, + .connected_device_name_resp = on_devicename, + .save_bondinfo = NULL, + .load_bondinfo = NULL, + }; + +static struct ble_gatt_central_ops_s ble_central_ops = + { + .write = on_write, + .read = on_read, + .notify = on_notify, + .database_discovery = on_discovered, + .descriptor_write = on_desc_write, + .descriptor_read = on_desc_read, + }; + +/* Connection handle */ + +static uint16_t g_connecthdl; + +/* Scan filter parameters */ + +static char g_filter_devname[BLE_APP_DEVNAME_LEN]; +static BLE_UUID g_filter_uuid; + +/* Private data */ + +static struct ble_app_private_t g_ble_app_priv; + +/* Discovery list */ + +static SLIST_HEAD(discover_list_s, discover_node_s) g_discover_list = + SLIST_HEAD_INITIALIZER(g_discover_list); + +/* Notify list */ + +static SLIST_HEAD(notify_list_s, notify_node_s) g_notify_list = + SLIST_HEAD_INITIALIZER(g_notify_list); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* BLE common operations */ + +static void unused_code +display_devinfo(uint8_t *addr, uint8_t type, const char *name) +{ + printf(name[0] != '\0' ? "Addr %s %02X:%02X:%02X:%02X:%02X:%02X >>%s<<\n" : + "Addr %s %02X:%02X:%02X:%02X:%02X:%02X\n", + type == BLE_ADDRTYPE_PUBLIC ? "Pub" : + type == BLE_ADDRTYPE_RAND_STATIC ? "Rnd" : + type == BLE_ADDRTYPE_RAND_PRIV_RESOLVABLE ? "Prv" : + type == BLE_ADDRTYPE_RAND_PRIV_NONRESOLVABLE ? "NRs" : "Unk", + addr[5], addr[4], addr[3], addr[2], addr[1], addr[0], + name[0] != '\0' ? name : ""); +} + +static void on_scan(BT_ADDR addr, uint8_t *data, uint8_t len) +{ + uint8_t addr_type; + struct ble_state_s state = {0}; + bool match = false; + char devname[BLE_APP_DEVNAME_LEN]; + + /* Get the BLE address in scanned data. */ + + addr_type = bleutil_get_addrtype(data, len); + + /* Search for the BLE device name in scanned data. */ + + memset(devname, 0, sizeof(devname)); + if (bleutil_get_devicename(data, len, devname)) + { + if (0 == strncmp(g_filter_devname, devname, sizeof(g_filter_devname))) + { + match = true; + } + } + +#if LOG_SCAN == 1 + display_devinfo(addr.address, addr_type, devname); +#endif + + /* Search for the service UUID in scanned data. */ + + if (bleutil_find_srvc_uuid(&g_filter_uuid, data, len)) + { + match = true; + } + + /* If the specified device is found by scan filter, connect the address */ + + if (match) + { + /* Stop scanning */ + + ble_cancel_scan(); + + /* Connect a found device. */ + + bleutil_add_btaddr(&state, &addr, addr_type); + ble_connect(&state); + } +} + +static void on_state_change(struct ble_state_s *state, bool connected, + uint8_t cause) +{ + struct ble_app_private_t *priv = &g_ble_app_priv; + + printf(connected ? "Connected " : "Disconnected "); + printf(" : Cause <%s> :", + cause == BLESTAT_SUCCESS ? "Success" : + cause == BLESTAT_MEMCAP_EXCD ? "Mem capacity exceed" : + cause == BLESTAT_CONNECT_TIMEOUT ? "Connection timeout" : + cause == BLESTAT_PEER_TERMINATED ? "Peripheral terminated" : + cause == BLESTAT_PEER_TERM_LOWRES ? "Peripheral low resource" : + cause == BLESTAT_PEER_TERM_POFF ? "Peripheral power off" : + cause == BLESTAT_TERMINATED ? "Terminated by self" : + cause == BLESTAT_DEVICE_BUSY ? "Device busy" : + cause == BLESTAT_PARAM_REJECTED ? "Negotiation breakup" : + cause == BLESTAT_CONNECT_FAILED ? "Connection failed" : + "Unspecified error"); + display_devinfo(state->bt_target_addr.address, + state->bt_target_addr_type, + state->bt_target_name); + + if (!connected) + { + /* Send the disconnected event to user application. */ + + priv->event = BLE_APP_DISCONNECTED; + sem_post(&priv->event_sync); + } + else + { + /* Keep connected device handle */ + + g_connecthdl = state->ble_connect_handle; + } +} + +static void on_mtusize(uint16_t handle, uint16_t sz) +{ + printf("[%s] MTU size is negotiated as :%d\n", __func__, sz); + + /* Start discovery */ + + ble_start_db_discovery(g_connecthdl); +} + +static void on_enc_result(uint16_t handle, bool result) +{ + struct ble_app_private_t *priv = &g_ble_app_priv; + + printf("[%s] Encryption : %s\n", __func__, result ? "Success" : "Fail"); + + /* Send the connected event to user application. */ + + priv->event = BLE_APP_CONNECTED; + sem_post(&priv->event_sync); +} + +static void on_devicename(const char *name) +{ + printf("[%s] Got device name : %s\n", __func__, name); +} + +/* BLE GATT Central operations */ + +static void on_write(uint16_t conn_handle, + struct ble_gatt_char_s *gatt_char) +{ + struct ble_app_private_t *priv = &g_ble_app_priv; + + priv->result = gatt_char->status; + sem_post(&priv->api_sync); +} + +static void unused_code +display_dumpdata(const char *funcname, struct ble_gatt_char_s *gatt_char) +{ + int i; + + printf("[%s]\n", funcname); + printf(" handle : 0x%04x\n", gatt_char->handle); + printf(" value len : %d\n", gatt_char->value.length); + printf(" value data: "); + for (i = 0; i < gatt_char->value.length; i++) + { + printf("%02x ", gatt_char->value.data[i]); + } + + printf("\n"); +} + +static void on_read(uint16_t conn_handle, + struct ble_gatt_char_s *gatt_char) +{ + struct ble_app_private_t *priv = &g_ble_app_priv; + + priv->len = gatt_char->value.length; + if (priv->len <= BLE_APP_BUFFER_LEN) + { +#if LOG_READ == 1 + display_dumpdata(__func__, gatt_char); +#endif + memcpy(priv->buffer, gatt_char->value.data, priv->len); + priv->result = 0; + } + else + { + priv->result = -1; + } + + sem_post(&priv->api_sync); +} + +static void on_notify(uint16_t conn_handle, + struct ble_gatt_char_s *gatt_char) +{ + struct notify_node_s *node; + int i; + +#if LOG_NOTIFY == 1 + display_dumpdata(__func__, gatt_char); +#endif + + SLIST_FOREACH(node, &g_notify_list, entries) + { + for (i = 0; i < node->nhandle; i++) + { + if (node->handles[i].handle == gatt_char->handle) + { + node->cb(gatt_char); + } + } + } +} + +static void unused_code +display_discovered(struct ble_gattc_db_disc_srv_s *srv, + struct ble_gattc_db_disc_char_s *ch) +{ + char srv_uuid[BLE_UUID_128BIT_STRING_BUFSIZE]; + char chr_uuid[BLE_UUID_128BIT_STRING_BUFSIZE]; + BLE_CHAR_PROP prop; + + bleutil_convert_uuid2str(&srv->srv_uuid, srv_uuid, BLE_UUID_128BIT_STRING_BUFSIZE); + bleutil_convert_uuid2str(&ch->characteristic.char_valuuid, chr_uuid, BLE_UUID_128BIT_STRING_BUFSIZE); + + printf("Service UUID: %s\n", srv_uuid); + printf(" Handle: 0x%04x (UUID: %s)\n", ch->characteristic.char_valhandle, chr_uuid); + + prop = ch->characteristic.char_prope; + printf(" Properties: %s%s%s%s%s%s%s%s\n", + prop.reserve ? "Extended, " : "", + prop.authSignedWr ? "Authenticated Signed Writes, " : "", + prop.indicate ? "Indicate, " : "", + prop.notify ? "Notify, " : "", + prop.write ? "Write, " : "", + prop.writeWoResp ? "Write Without Response, " : "", + prop.read ? "Read, " : "", + prop.broadcast ? "Broadcast, " : ""); + + if (ch->cafd_handle != BLE_GATT_INVALID_ATTRIBUTE_HANDLE) + { + printf(" Handle: 0x%04x (Characteristic Aggregate Format)\n", + ch->cafd_handle); + } + + if (ch->cpfd_handle != BLE_GATT_INVALID_ATTRIBUTE_HANDLE) + { + printf(" Handle: 0x%04x (Characteristic Presentation Format)\n", + ch->cpfd_handle); + } + + if (ch->sccd_handle != BLE_GATT_INVALID_ATTRIBUTE_HANDLE) + { + printf(" Handle: 0x%04x (Server Characteristic Configuration)\n", + ch->sccd_handle); + } + + if (ch->cccd_handle != BLE_GATT_INVALID_ATTRIBUTE_HANDLE) + { + printf(" Handle: 0x%04x (Client Characteristic Configuration)\n", + ch->cccd_handle); + } + + if (ch->cudd_handle != BLE_GATT_INVALID_ATTRIBUTE_HANDLE) + { + printf(" Handle: 0x%04x (Characteristic User Description)\n", + ch->cudd_handle); + } + + if (ch->cepd_handle != BLE_GATT_INVALID_ATTRIBUTE_HANDLE) + { + printf(" Handle: 0x%04x (Characteristic Extended Properties)\n", + ch->cepd_handle); + } +} + +static void on_discovered(struct ble_gatt_event_db_discovery_t *db_disc) +{ + int svcs; + int chrs; + int srv_num = db_disc->params.db_discovery.srv_count; + struct ble_gattc_db_disc_srv_s *srv = db_disc->params.db_discovery.services; + struct ble_gattc_db_disc_char_s *ch; + struct discover_node_s *node; + int i; + uint16_t handle; + uint16_t cccd_handle; + + for (svcs = 0; svcs < srv_num; svcs++, srv++) + { + ch = srv->characteristics; + for (chrs = 0; chrs < srv->char_count; chrs++, ch++) + { +#if LOG_DISCOVERY == 1 + display_discovered(srv, ch); +#endif + SLIST_FOREACH(node, &g_discover_list, entries) + { + if (bleutil_uuidcmp(&node->uuid, &ch->characteristic.char_valuuid) == 0) + { + handle = ch->characteristic.char_valhandle; + cccd_handle = ch->cccd_handle; + + for (i = 0; i < node->nhandle; i++) + { + /* Check if already registered. */ + + if ((node->handles[i].handle == handle) && + (node->handles[i].cccd_handle == cccd_handle)) + { + break; + } + } + + if ((i == node->nhandle) && (i < MAX_HANDLES_OF_UUID)) + { + /* Register new handle */ + + node->handles[i].handle = handle; + node->handles[i].cccd_handle = cccd_handle; + node->nhandle++; + } + + node->cb(ch); + } + } + } + } + + if ((db_disc->state.end_handle != 0xffff) && + (db_disc->state.end_handle != 0x0000)) + { + /* Continue to find next handle. */ + + ble_continue_db_discovery(db_disc->state.end_handle + 1, + g_connecthdl); + } + else + { + /* Pairing after discovery is complete. */ + + printf("[%s] Paring to BLE device\n", __func__); + ble_pairing(g_connecthdl); + } +} + +static void on_desc_write(uint16_t connhdl, uint16_t charhdl, int result) +{ + struct ble_app_private_t *priv = &g_ble_app_priv; + + priv->result = result; + sem_post(&priv->api_sync); +} + +static void on_desc_read(uint16_t connhdl, uint16_t charhdl, + uint8_t *data, uint16_t len) +{ + struct ble_app_private_t *priv = &g_ble_app_priv; + + priv->len = len; + if (priv->len <= BLE_APP_BUFFER_LEN) + { + memcpy(priv->buffer, data, priv->len); + priv->result = 0; + } + else + { + priv->result = -1; + } + + sem_post(&priv->api_sync); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/* BLE GATT synchronous API */ + +int write_gatt_descriptor(uint16_t handle, + uint8_t *data, int len) +{ + int ret; + struct ble_app_private_t *priv = &g_ble_app_priv; + + ret = ble_descriptor_write(g_connecthdl, handle, data, len); + if (ret == BT_SUCCESS) + { + sem_wait(&priv->api_sync); + ret = priv->result; + } + + return ret; +} + +int read_gatt_descriptor(uint16_t handle, uint8_t *data, int *len) +{ + int ret; + struct ble_app_private_t *priv = &g_ble_app_priv; + + *len = 0; + + ret = ble_descriptor_read(g_connecthdl, handle); + if (ret == BT_SUCCESS) + { + sem_wait(&priv->api_sync); + ret = priv->result; + if (ret == 0) + { + *len = priv->len; + memcpy(data, priv->buffer, priv->len); + } + } + + return ret; +} + +int write_gatt_char(uint16_t handle, uint8_t *data, int len, bool response) +{ + int ret; + struct ble_app_private_t *priv = &g_ble_app_priv; + + ret = ble_write_characteristic(g_connecthdl, handle, data, len, response); + if (response && (ret == BT_SUCCESS)) + { + sem_wait(&priv->api_sync); + ret = priv->result; + } + + return ret; +} + +int read_gatt_char(uint16_t handle, uint8_t *data, int *len) +{ + int ret; + struct ble_app_private_t *priv = &g_ble_app_priv; + + *len = 0; + + ret = ble_read_characteristic(g_connecthdl, handle); + if (ret == BT_SUCCESS) + { + sem_wait(&priv->api_sync); + ret = priv->result; + if (ret == 0) + { + *len = priv->len; + memcpy(data, priv->buffer, priv->len); + } + } + + return ret; +} + +int scan_filter_uuid(BLE_UUID *uuid) +{ + g_filter_uuid = *uuid; + return 0; +} + +int scan_filter_device_name(const char *name) +{ + strncpy(g_filter_devname, name, sizeof(g_filter_devname) - 1); + return 0; +} + +int register_discover(BLE_UUID *uuid, discover_cb_t cb) +{ + struct discover_node_s *node; + + node = malloc(sizeof(struct discover_node_s)); + if (!node) + { + return -ENOMEM; + } + + /* Insert into discover list. */ + + node->cb = cb; + node->uuid = *uuid; + node->nhandle = 0; + SLIST_INSERT_HEAD(&g_discover_list, node, entries); + + return 0; +} + +int unregister_discover(BLE_UUID *uuid) +{ + struct discover_node_s *node; + struct discover_node_s *tmp; + + /* Remove from discover list. */ + + SLIST_FOREACH_SAFE(node, &g_discover_list, entries, tmp) + { + if (0 == bleutil_uuidcmp(&node->uuid, uuid)) + { + SLIST_REMOVE(&g_discover_list, node, discover_node_s, entries); + free(node); + } + } + + return 0; +} + +int start_notify(BLE_UUID *uuid, notify_cb_t cb) +{ + int ret = 0; + uint16_t notify_en = 1; + struct notify_node_s *nnode; + struct discover_node_s *dnode; + int nhandle = 0; + int i; + uint16_t cccd_handle; + + /* Get the handle numbers from discovered UUID. */ + + SLIST_FOREACH(dnode, &g_discover_list, entries) + { + if (bleutil_uuidcmp(&dnode->uuid, uuid) == 0) + { + nhandle = dnode->nhandle; + break; + } + } + + if (nhandle == 0) + { + return -ENOENT; + } + + /* Insert into notify list. */ + + nnode = malloc(sizeof(struct notify_node_s)); + if (!nnode) + { + return -ENOMEM; + } + + nnode->cb = cb; + nnode->uuid = *uuid; + nnode->nhandle = nhandle; + memcpy(nnode->handles, dnode->handles, sizeof(nnode->handles)); + SLIST_INSERT_HEAD(&g_notify_list, nnode, entries); + + /* Enable notification on CCCD handle. */ + + for (i = 0; i < nhandle; i++) + { + cccd_handle = dnode->handles[i].cccd_handle; + if (cccd_handle != BLE_GATT_INVALID_ATTRIBUTE_HANDLE) + { + ret = write_gatt_descriptor(cccd_handle, + (uint8_t *)¬ify_en, sizeof(notify_en)); + if (ret != BT_SUCCESS) + { + printf("ERROR: Failed to enable notification ret=%d\n", ret); + } + } + } + + return ret; +} + +int stop_notify(BLE_UUID *uuid) +{ + int ret = 0; + uint16_t notify_en = 0; + struct notify_node_s *node; + struct notify_node_s *tmp; + int i; + uint16_t cccd_handle; + + /* Remove from notify list. */ + + SLIST_FOREACH_SAFE(node, &g_notify_list, entries, tmp) + { + if (bleutil_uuidcmp(&node->uuid, uuid) == 0) + { + for (i = 0; i < node->nhandle; i++) + { + cccd_handle = node->handles[i].cccd_handle; + if (cccd_handle != BLE_GATT_INVALID_ATTRIBUTE_HANDLE) + { + ret = write_gatt_descriptor(cccd_handle, + (uint8_t *)¬ify_en, sizeof(notify_en)); + } + } + + SLIST_REMOVE(&g_notify_list, node, notify_node_s, entries); + free(node); + } + } + + return ret; +} + +int ble_app_init(void) +{ + int ret = 0; + struct ble_app_private_t *priv = &g_ble_app_priv; + + /* Initialize private data. */ + + sem_init(&priv->event_sync, 0, 0); + sem_init(&priv->api_sync, 0, 0); + + memset(g_filter_devname, 0, sizeof(g_filter_devname)); + + /* Initialize BT/BLE */ + + bt_init(); + + ble_register_common_cb(&ble_common_ops); + ble_register_gatt_central_cb(&ble_central_ops); + + return ret; +} + +enum ble_app_event ble_app_wait_event(void) +{ + struct ble_app_private_t *priv = &g_ble_app_priv; + + sem_wait(&priv->event_sync); + return priv->event; +} diff --git a/examples/ble_mouse_central/ble_central_app.h b/examples/ble_mouse_central/ble_central_app.h new file mode 100644 index 000000000..519a8d325 --- /dev/null +++ b/examples/ble_mouse_central/ble_central_app.h @@ -0,0 +1,131 @@ +/**************************************************************************** + * examples/ble_mouse_central/ble_central_app.h + * + * Copyright 2024 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __EXAMPLES_BLE_MOUSE_CENTRAL_BLE_CENTRAL_APP_H +#define __EXAMPLES_BLE_MOUSE_CENTRAL_BLE_CENTRAL_APP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define BLE_UUID16(_uuid) \ +{ \ + .type = BLE_UUID_TYPE_BASEALIAS_BTSIG, \ + .value.alias.uuidAlias = _uuid, \ +} + +#define BLE_UUID128(_uuid) \ +{ \ + .type = BLE_UUID_TYPE_UUID128, \ + .value.uuid128 = {_uuid}, \ +} + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* BLE app event */ + +enum ble_app_event +{ + BLE_APP_CONNECTED, + BLE_APP_DISCONNECTED, +}; + +/* Discovery callback */ + +typedef void (*discover_cb_t)(struct ble_gattc_db_disc_char_s *gatt_disc_char); + +/* Notify callback */ + +typedef void (*notify_cb_t)(struct ble_gatt_char_s *gatt_char); + +/**************************************************************************** + * Public Functions Prototype + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/* BLE GATT synchronous API + * These APIs can be called only from application threads. + * They must not be called from notify callback threads. + */ + +int write_gatt_descriptor(uint16_t handle, uint8_t *data, int len); +int read_gatt_descriptor(uint16_t handle, uint8_t *data, int *len); +int write_gatt_char(uint16_t handle, uint8_t *data, int len, bool response); +int read_gatt_char(uint16_t handle, uint8_t *data, int *len); + +/* BLE Scan filter API */ + +int scan_filter_uuid(BLE_UUID *uuid); +int scan_filter_device_name(const char *name); + +/* BLE Register discovery API */ + +int register_discover(BLE_UUID *uuid, discover_cb_t cb); +int unregister_discover(BLE_UUID *uuid); + +/* BLE Notify API */ + +int start_notify(BLE_UUID *uuid, notify_cb_t cb); +int stop_notify(BLE_UUID *uuid); + +/* BLE App API */ + +int ble_app_init(void); +enum ble_app_event ble_app_wait_event(void); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __EXAMPLES_BLE_MOUSE_CENTRAL_BLE_CENTRAL_APP_H */ diff --git a/examples/ble_mouse_central/ble_mouse_central_main.c b/examples/ble_mouse_central/ble_mouse_central_main.c new file mode 100644 index 000000000..2585bd74f --- /dev/null +++ b/examples/ble_mouse_central/ble_mouse_central_main.c @@ -0,0 +1,216 @@ +/**************************************************************************** + * examples/ble_mouse_central/ble_mouse_central_main.c + * + * Copyright 2024 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_EXAMPLES_BLE_MOUSE_INPUT_DEVICE +#include +#endif +#include "ble_central_app.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* BLE HID Service UUID */ + +#define BLE_UUID_HID_SERVICE 0x1812 + +/* BLE Report Characteristic UUID */ + +#define BLE_UUID_REPORT_CHAR 0x2A4D + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Mouse device specific data */ + +begin_packed_struct struct mouse_data_t +{ + uint8_t buttons; + int16_t x; + int16_t y; + int8_t wheel; + uint8_t pan; +} end_packed_struct; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_BLE_MOUSE_INPUT_DEVICE +static struct mouse_lowerhalf_s g_mouselower; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void mouse_discover(struct ble_gattc_db_disc_char_s *gatt_disc_char) +{ + printf("%s()\n", __func__); +} + +static void mouse_notify(struct ble_gatt_char_s *gatt_char) +{ + /* Received notify from mouse device. + * The mouse data structure depends on the mouse device + * and should be customized as needed. + */ + + struct mouse_data_t *data = (struct mouse_data_t *)gatt_char->value.data; + +#ifdef CONFIG_EXAMPLES_BLE_MOUSE_INPUT_DEVICE + struct mouse_report_s sample; + + sample.buttons = data->buttons; + sample.x = data->x; + sample.y = data->y; +# ifdef CONFIG_INPUT_MOUSE_WHEEL + sample.wheel = data->wheel; +# endif + mouse_event(g_mouselower.priv, &sample); +#else + printf("button = %d (x, y) = (%4d, %4d) wheel= %3d\n", + data->buttons, data->x, data->y, data->wheel); +#endif +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + int ret; + char myname[] = "BLE_MOUSE_CENTRAL"; + BT_ADDR myaddr = {{0x19, 0x84, 0x06, 0x14, 0xAB, 0xCD}}; + + BLE_UUID hid_uuid = BLE_UUID16(BLE_UUID_HID_SERVICE); + BLE_UUID report_uuid = BLE_UUID16(BLE_UUID_REPORT_CHAR); + + /* Initialize BLE central application. */ + + ble_app_init(); + + ble_set_name(myname); + ble_set_address(&myaddr); + + ret = bt_enable(); + if (ret != BT_SUCCESS) + { + printf("ERROR: bt_enable() ret=%d\n", ret); + return ret; + } + + ret = ble_enable(); + if (ret != BT_SUCCESS) + { + printf("ERROR: ble_enable() ret=%d\n", ret); + goto error; + } + + /* Set scan filter to connect if the specified UUID is found. */ + + scan_filter_uuid(&hid_uuid); + + /* Discover the report characteristic */ + + register_discover(&report_uuid, mouse_discover); + +#ifdef CONFIG_EXAMPLES_BLE_MOUSE_INPUT_DEVICE + ret = mouse_register(&g_mouselower, CONFIG_EXAMPLES_BLE_MOUSE_INPUT_DEVPATH, 1); + if (ret < 0) + { + printf("[%s] mouse_register failed. ret = %d\n", __func__, ret); + goto error; + } +#endif + + ret = ble_start_scan(false); + if (ret != BT_SUCCESS) + { + printf("[%s] ble_start_scan() failed. ret = %d\n", __func__, ret); + goto error; + } + + while (1) + { + switch (ble_app_wait_event()) + { + case BLE_APP_CONNECTED: + + /* Enable HID report notification. */ + + start_notify(&report_uuid, mouse_notify); + break; + + case BLE_APP_DISCONNECTED: + + /* Disable HID report notification. */ + + stop_notify(&report_uuid); + + /* Re-scan after disconnection. */ + + ble_start_scan(false); + break; + default: + break; + } + } + +error: + ble_disable(); + bt_disable(); + + return 0; +} diff --git a/sdk/modules/include/audiolite/al_source.h b/examples/ble_mouse_central/mouse_reader_main.c similarity index 66% rename from sdk/modules/include/audiolite/al_source.h rename to examples/ble_mouse_central/mouse_reader_main.c index cbeeba40b..5b908c2cf 100644 --- a/sdk/modules/include/audiolite/al_source.h +++ b/examples/ble_mouse_central/mouse_reader_main.c @@ -1,7 +1,7 @@ /**************************************************************************** - * modules/include/audiolite/al_source.h + * examples/ble_mouse_central/mouse_reader_main.c * - * Copyright 2023 Sony Semiconductor Solutions Corporation + * Copyright 2024 Sony Semiconductor Solutions Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,44 +33,60 @@ * ****************************************************************************/ -#ifndef __INCLUDE_AUDIOLITE_SOURCE_H -#define __INCLUDE_AUDIOLITE_SOURCE_H - /**************************************************************************** * Included Files ****************************************************************************/ #include -#include +#include +#include +#include /**************************************************************************** - * Class Definitions + * Public Functions ****************************************************************************/ -/**************************************************************************** - * class: audiolite_source - ****************************************************************************/ - -class audiolite_source : public audiolite_component +int main(int argc, FAR char *argv[]) { - public: - audiolite_source(int inputnum = 1, - int outputnum = 1, - int depth = 4, - bool is_sync = true, - int prio = -1, - int stack_sz = -1) - : audiolite_component(inputnum, outputnum, depth, - is_sync, prio, stack_sz) + int fd; + int ret; + struct mouse_report_s sample; + + /* Open the mouse device for blocking reading */ + + fd = open(CONFIG_EXAMPLES_BLE_MOUSE_INPUT_DEVPATH, O_RDONLY); + if (fd < 0) { - }; + printf("ERROR: open ret=%d, errno=%d\n", fd, errno); + return -ENODEV; + } + + /* Display the collected mouse samples */ + + for (; ; ) + { + /* Wait for data and read */ + + ret = read(fd, &sample, sizeof(sample)); + if (ret < 0) + { + printf("ERROR: read ret=%d, errno=%d\n", ret, errno); + break; + } - virtual ~audiolite_source(){}; + printf("Button: %d (X, Y): (%4d, %4d)" +#ifdef CONFIG_INPUT_MOUSE_WHEEL + " Wheel: %d" +#endif + "\n", + sample.buttons, sample.x, sample.y +#ifdef CONFIG_INPUT_MOUSE_WHEEL + , sample.wheel +#endif + ); + } - virtual int start() = 0; - virtual void stop() = 0; - virtual void pause() = 0; - virtual int resume() = 0; -}; + close(fd); -#endif /* __INCLUDE_AUDIOLITE_SOURCE_H */ + return ret; +} diff --git a/examples/ble_toio_central/Kconfig b/examples/ble_toio_central/Kconfig new file mode 100644 index 000000000..4af5df83b --- /dev/null +++ b/examples/ble_toio_central/Kconfig @@ -0,0 +1,29 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config EXAMPLES_BLE_TOIO_CENTRAL + tristate "BLE toio Central example" + default n + ---help--- + Enable the ble_toio_central app + +if EXAMPLES_BLE_TOIO_CENTRAL + +config EXAMPLES_BLE_TOIO_CENTRAL_PROGNAME + string "Program name" + default "ble_toio_central" + ---help--- + This is the name of the program that will be use when the NSH ELF + program is installed. + +config EXAMPLES_BLE_TOIO_CENTRAL_PRIORITY + int "ble_toio_central task priority" + default 100 + +config EXAMPLES_BLE_TOIO_CENTRAL_STACKSIZE + int "ble_toio_central stack size" + default DEFAULT_TASK_STACKSIZE + +endif # EXAMPLES_BLE_TOIO_CENTRAL diff --git a/examples/ble_toio_central/Make.defs b/examples/ble_toio_central/Make.defs new file mode 100644 index 000000000..5db07a230 --- /dev/null +++ b/examples/ble_toio_central/Make.defs @@ -0,0 +1,38 @@ +############################################################################ +# examples/ble_toio_central/Make.defs +# +# Copyright 2024 Sony Semiconductor Solutions Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name of Sony Semiconductor Solutions Corporation nor +# the names of its contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +ifneq ($(CONFIG_EXAMPLES_BLE_TOIO_CENTRAL),) +CONFIGURED_APPS += ble_toio_central +endif diff --git a/examples/ble_toio_central/Makefile b/examples/ble_toio_central/Makefile new file mode 100644 index 000000000..f9d23d847 --- /dev/null +++ b/examples/ble_toio_central/Makefile @@ -0,0 +1,47 @@ +############################################################################ +# examples/ble_toio_central/Makefile +# +# Copyright 2024 Sony Semiconductor Solutions Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name of Sony Semiconductor Solutions Corporation nor +# the names of its contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +include $(APPDIR)/Make.defs +-include $(SDKDIR)/Make.defs + +PROGNAME = $(CONFIG_EXAMPLES_BLE_TOIO_CENTRAL_PROGNAME) +PRIORITY = $(CONFIG_EXAMPLES_BLE_TOIO_CENTRAL_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_BLE_TOIO_CENTRAL_STACKSIZE) +MODULE = $(CONFIG_EXAMPLES_BLE_TOIO_CENTRAL) + +CSRCS = ble_central_app.c +MAINSRC = ble_toio_central_main.cxx + +include $(APPDIR)/Application.mk diff --git a/examples/ble_toio_central/ble_central_app.c b/examples/ble_toio_central/ble_central_app.c new file mode 100644 index 000000000..89a49da55 --- /dev/null +++ b/examples/ble_toio_central/ble_central_app.c @@ -0,0 +1,799 @@ +/**************************************************************************** + * examples/ble_toio_central/ble_central_app.c + * + * Copyright 2024 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ble_central_app.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define BLE_APP_BUFFER_LEN 64 +#define BLE_APP_DEVNAME_LEN 32 + +#define BLE_APP_DEFAULT_MTU_SIZE 23 + +/* Maximum number of handles with the same UUID */ + +#define MAX_HANDLES_OF_UUID 8 + +/* Print the detail log (1:enable, 0:disable) */ + +#define LOG_SCAN 1 +#define LOG_DISCOVERY 1 +#define LOG_NOTIFY 0 +#define LOG_READ 0 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct handle_set_s +{ + uint16_t handle; + uint16_t cccd_handle; +}; + +/* Discovery list node */ +struct discover_node_s +{ + discover_cb_t cb; + BLE_UUID uuid; + int nhandle; + struct handle_set_s handles[MAX_HANDLES_OF_UUID]; + SLIST_ENTRY(discover_node_s) entries; +}; + +/* Notify list node */ + +struct notify_node_s +{ + notify_cb_t cb; + BLE_UUID uuid; + int nhandle; + struct handle_set_s handles[MAX_HANDLES_OF_UUID]; + SLIST_ENTRY(notify_node_s) entries; +}; + +/* Private structure for BLE central app */ + +struct ble_app_private_t +{ + enum ble_app_event event; + sem_t event_sync; + int result; + uint8_t buffer[BLE_APP_BUFFER_LEN]; + int len; + sem_t api_sync; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void on_scan(BT_ADDR addr, uint8_t *data, uint8_t len); +static void on_state_change(struct ble_state_s *state, bool connected, uint8_t cause); +static void on_mtusize(uint16_t handle, uint16_t sz); +static void on_discovered(struct ble_gatt_event_db_discovery_t *db_disc); +static void on_enc_result(uint16_t handle, bool result); +static void on_devicename(const char *name); + +static void on_write(uint16_t conn_handle, struct ble_gatt_char_s *gatt_char); +static void on_read(uint16_t conn_handle, struct ble_gatt_char_s *gatt_char); +static void on_notify(uint16_t conn_handle, struct ble_gatt_char_s *gatt_char); +static void on_desc_write(uint16_t connhdl, uint16_t charhdl, int result); +static void on_desc_read(uint16_t connhdl, uint16_t charhdl, uint8_t *data, uint16_t len); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct ble_common_ops_s ble_common_ops = + { + .scan_result = on_scan, + .mtusize = on_mtusize, + .connect_status_changed = on_state_change, + .encryption_result = on_enc_result, + .connected_device_name_resp = on_devicename, + .save_bondinfo = NULL, + .load_bondinfo = NULL, + }; + +static struct ble_gatt_central_ops_s ble_central_ops = + { + .write = on_write, + .read = on_read, + .notify = on_notify, + .database_discovery = on_discovered, + .descriptor_write = on_desc_write, + .descriptor_read = on_desc_read, + }; + +/* Connection handle */ + +static uint16_t g_connecthdl; + +/* Scan filter parameters */ + +static char g_filter_devname[BLE_APP_DEVNAME_LEN]; +static BLE_UUID g_filter_uuid; + +/* Private data */ + +static struct ble_app_private_t g_ble_app_priv; + +/* Discovery list */ + +static SLIST_HEAD(discover_list_s, discover_node_s) g_discover_list = + SLIST_HEAD_INITIALIZER(g_discover_list); + +/* Notify list */ + +static SLIST_HEAD(notify_list_s, notify_node_s) g_notify_list = + SLIST_HEAD_INITIALIZER(g_notify_list); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* BLE common operations */ + +static void unused_code +display_devinfo(uint8_t *addr, uint8_t type, const char *name) +{ + printf(name[0] != '\0' ? "Addr %s %02X:%02X:%02X:%02X:%02X:%02X >>%s<<\n" : + "Addr %s %02X:%02X:%02X:%02X:%02X:%02X\n", + type == BLE_ADDRTYPE_PUBLIC ? "Pub" : + type == BLE_ADDRTYPE_RAND_STATIC ? "Rnd" : + type == BLE_ADDRTYPE_RAND_PRIV_RESOLVABLE ? "Prv" : + type == BLE_ADDRTYPE_RAND_PRIV_NONRESOLVABLE ? "NRs" : "Unk", + addr[5], addr[4], addr[3], addr[2], addr[1], addr[0], + name[0] != '\0' ? name : ""); +} + +static void on_scan(BT_ADDR addr, uint8_t *data, uint8_t len) +{ + uint8_t addr_type; + struct ble_state_s state = {0}; + bool match = false; + char devname[BLE_APP_DEVNAME_LEN]; + + /* Get the BLE address in scanned data. */ + + addr_type = bleutil_get_addrtype(data, len); + + /* Search for the BLE device name in scanned data. */ + + memset(devname, 0, sizeof(devname)); + if (bleutil_get_devicename(data, len, devname)) + { + if (0 == strncmp(g_filter_devname, devname, sizeof(g_filter_devname))) + { + match = true; + } + } + +#if LOG_SCAN == 1 + display_devinfo(addr.address, addr_type, devname); +#endif + + /* Search for the service UUID in scanned data. */ + + if (bleutil_find_srvc_uuid(&g_filter_uuid, data, len)) + { + match = true; + } + + /* If the specified device is found by scan filter, connect the address */ + + if (match) + { + /* Stop scanning */ + + ble_cancel_scan(); + + /* Connect a found device. */ + + bleutil_add_btaddr(&state, &addr, addr_type); + ble_connect(&state); + } +} + +static void on_state_change(struct ble_state_s *state, bool connected, + uint8_t cause) +{ + struct ble_app_private_t *priv = &g_ble_app_priv; + + printf(connected ? "Connected " : "Disconnected "); + printf(" : Cause <%s> :", + cause == BLESTAT_SUCCESS ? "Success" : + cause == BLESTAT_MEMCAP_EXCD ? "Mem capacity exceed" : + cause == BLESTAT_CONNECT_TIMEOUT ? "Connection timeout" : + cause == BLESTAT_PEER_TERMINATED ? "Peripheral terminated" : + cause == BLESTAT_PEER_TERM_LOWRES ? "Peripheral low resource" : + cause == BLESTAT_PEER_TERM_POFF ? "Peripheral power off" : + cause == BLESTAT_TERMINATED ? "Terminated by self" : + cause == BLESTAT_DEVICE_BUSY ? "Device busy" : + cause == BLESTAT_PARAM_REJECTED ? "Negotiation breakup" : + cause == BLESTAT_CONNECT_FAILED ? "Connection failed" : + "Unspecified error"); + display_devinfo(state->bt_target_addr.address, + state->bt_target_addr_type, + state->bt_target_name); + + if (!connected) + { + /* Send the disconnected event to user application. */ + + priv->event = BLE_APP_DISCONNECTED; + sem_post(&priv->event_sync); + } + else + { + /* Keep connected device handle */ + + g_connecthdl = state->ble_connect_handle; + + /* MTU exchange is requested by the peripheral device after connection. + * If set the default MTU size, prevent the central from requesting MTU. + */ + + ble_set_request_mtusize(BLE_APP_DEFAULT_MTU_SIZE); + } +} + +static void on_mtusize(uint16_t handle, uint16_t sz) +{ + printf("[%s] MTU size is negotiated as :%d\n", __func__, sz); + + /* Start discovery */ + + ble_start_db_discovery(g_connecthdl); +} + +static void on_enc_result(uint16_t handle, bool result) +{ + struct ble_app_private_t *priv = &g_ble_app_priv; + + printf("[%s] Encryption : %s\n", __func__, result ? "Success" : "Fail"); + + /* Send the connected event to user application. */ + + priv->event = BLE_APP_CONNECTED; + sem_post(&priv->event_sync); +} + +static void on_devicename(const char *name) +{ + printf("[%s] Got device name : %s\n", __func__, name); +} + +/* BLE GATT Central operations */ + +static void on_write(uint16_t conn_handle, + struct ble_gatt_char_s *gatt_char) +{ + struct ble_app_private_t *priv = &g_ble_app_priv; + + priv->result = gatt_char->status; + sem_post(&priv->api_sync); +} + +static void unused_code +display_dumpdata(const char *funcname, struct ble_gatt_char_s *gatt_char) +{ + int i; + + printf("[%s]\n", funcname); + printf(" handle : 0x%04x\n", gatt_char->handle); + printf(" value len : %d\n", gatt_char->value.length); + printf(" value data: "); + for (i = 0; i < gatt_char->value.length; i++) + { + printf("%02x ", gatt_char->value.data[i]); + } + + printf("\n"); +} + +static void on_read(uint16_t conn_handle, + struct ble_gatt_char_s *gatt_char) +{ + struct ble_app_private_t *priv = &g_ble_app_priv; + + priv->len = gatt_char->value.length; + if (priv->len <= BLE_APP_BUFFER_LEN) + { +#if LOG_READ == 1 + display_dumpdata(__func__, gatt_char); +#endif + memcpy(priv->buffer, gatt_char->value.data, priv->len); + priv->result = 0; + } + else + { + priv->result = -1; + } + + sem_post(&priv->api_sync); +} + +static void on_notify(uint16_t conn_handle, + struct ble_gatt_char_s *gatt_char) +{ + struct notify_node_s *node; + int i; + +#if LOG_NOTIFY == 1 + display_dumpdata(__func__, gatt_char); +#endif + + SLIST_FOREACH(node, &g_notify_list, entries) + { + for (i = 0; i < node->nhandle; i++) + { + if (node->handles[i].handle == gatt_char->handle) + { + node->cb(gatt_char); + } + } + } +} + +static void unused_code +display_discovered(struct ble_gattc_db_disc_srv_s *srv, + struct ble_gattc_db_disc_char_s *ch) +{ + char srv_uuid[BLE_UUID_128BIT_STRING_BUFSIZE]; + char chr_uuid[BLE_UUID_128BIT_STRING_BUFSIZE]; + BLE_CHAR_PROP prop; + + bleutil_convert_uuid2str(&srv->srv_uuid, srv_uuid, BLE_UUID_128BIT_STRING_BUFSIZE); + bleutil_convert_uuid2str(&ch->characteristic.char_valuuid, chr_uuid, BLE_UUID_128BIT_STRING_BUFSIZE); + + printf("Service UUID: %s\n", srv_uuid); + printf(" Handle: 0x%04x (UUID: %s)\n", ch->characteristic.char_valhandle, chr_uuid); + + prop = ch->characteristic.char_prope; + printf(" Properties: %s%s%s%s%s%s%s%s\n", + prop.reserve ? "Extended, " : "", + prop.authSignedWr ? "Authenticated Signed Writes, " : "", + prop.indicate ? "Indicate, " : "", + prop.notify ? "Notify, " : "", + prop.write ? "Write, " : "", + prop.writeWoResp ? "Write Without Response, " : "", + prop.read ? "Read, " : "", + prop.broadcast ? "Broadcast, " : ""); + + if (ch->cafd_handle != BLE_GATT_INVALID_ATTRIBUTE_HANDLE) + { + printf(" Handle: 0x%04x (Characteristic Aggregate Format)\n", + ch->cafd_handle); + } + + if (ch->cpfd_handle != BLE_GATT_INVALID_ATTRIBUTE_HANDLE) + { + printf(" Handle: 0x%04x (Characteristic Presentation Format)\n", + ch->cpfd_handle); + } + + if (ch->sccd_handle != BLE_GATT_INVALID_ATTRIBUTE_HANDLE) + { + printf(" Handle: 0x%04x (Server Characteristic Configuration)\n", + ch->sccd_handle); + } + + if (ch->cccd_handle != BLE_GATT_INVALID_ATTRIBUTE_HANDLE) + { + printf(" Handle: 0x%04x (Client Characteristic Configuration)\n", + ch->cccd_handle); + } + + if (ch->cudd_handle != BLE_GATT_INVALID_ATTRIBUTE_HANDLE) + { + printf(" Handle: 0x%04x (Characteristic User Description)\n", + ch->cudd_handle); + } + + if (ch->cepd_handle != BLE_GATT_INVALID_ATTRIBUTE_HANDLE) + { + printf(" Handle: 0x%04x (Characteristic Extended Properties)\n", + ch->cepd_handle); + } +} + +static void on_discovered(struct ble_gatt_event_db_discovery_t *db_disc) +{ + int svcs; + int chrs; + int srv_num = db_disc->params.db_discovery.srv_count; + struct ble_gattc_db_disc_srv_s *srv = db_disc->params.db_discovery.services; + struct ble_gattc_db_disc_char_s *ch; + struct discover_node_s *node; + int i; + uint16_t handle; + uint16_t cccd_handle; + + for (svcs = 0; svcs < srv_num; svcs++, srv++) + { + ch = srv->characteristics; + for (chrs = 0; chrs < srv->char_count; chrs++, ch++) + { +#if LOG_DISCOVERY == 1 + display_discovered(srv, ch); +#endif + SLIST_FOREACH(node, &g_discover_list, entries) + { + if (bleutil_uuidcmp(&node->uuid, &ch->characteristic.char_valuuid) == 0) + { + handle = ch->characteristic.char_valhandle; + cccd_handle = ch->cccd_handle; + + for (i = 0; i < node->nhandle; i++) + { + /* Check if already registered. */ + + if ((node->handles[i].handle == handle) && + (node->handles[i].cccd_handle == cccd_handle)) + { + break; + } + } + + if ((i == node->nhandle) && (i < MAX_HANDLES_OF_UUID)) + { + /* Register new handle */ + + node->handles[i].handle = handle; + node->handles[i].cccd_handle = cccd_handle; + node->nhandle++; + } + + node->cb(ch); + } + } + } + } + + if ((db_disc->state.end_handle != 0xffff) && + (db_disc->state.end_handle != 0x0000)) + { + /* Continue to find next handle. */ + + ble_continue_db_discovery(db_disc->state.end_handle + 1, + g_connecthdl); + } + else + { + /* Pairing after discovery is complete. */ + + printf("[%s] Paring to BLE device\n", __func__); + ble_pairing(g_connecthdl); + } +} + +static void on_desc_write(uint16_t connhdl, uint16_t charhdl, int result) +{ + struct ble_app_private_t *priv = &g_ble_app_priv; + + priv->result = result; + sem_post(&priv->api_sync); +} + +static void on_desc_read(uint16_t connhdl, uint16_t charhdl, + uint8_t *data, uint16_t len) +{ + struct ble_app_private_t *priv = &g_ble_app_priv; + + priv->len = len; + if (priv->len <= BLE_APP_BUFFER_LEN) + { + memcpy(priv->buffer, data, priv->len); + priv->result = 0; + } + else + { + priv->result = -1; + } + + sem_post(&priv->api_sync); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/* BLE GATT synchronous API */ + +int write_gatt_descriptor(uint16_t handle, + uint8_t *data, int len) +{ + int ret; + struct ble_app_private_t *priv = &g_ble_app_priv; + + ret = ble_descriptor_write(g_connecthdl, handle, data, len); + if (ret == BT_SUCCESS) + { + sem_wait(&priv->api_sync); + ret = priv->result; + } + + return ret; +} + +int read_gatt_descriptor(uint16_t handle, uint8_t *data, int *len) +{ + int ret; + struct ble_app_private_t *priv = &g_ble_app_priv; + + *len = 0; + + ret = ble_descriptor_read(g_connecthdl, handle); + if (ret == BT_SUCCESS) + { + sem_wait(&priv->api_sync); + ret = priv->result; + if (ret == 0) + { + *len = priv->len; + memcpy(data, priv->buffer, priv->len); + } + } + + return ret; +} + +int write_gatt_char(uint16_t handle, uint8_t *data, int len, bool response) +{ + int ret; + struct ble_app_private_t *priv = &g_ble_app_priv; + + ret = ble_write_characteristic(g_connecthdl, handle, data, len, response); + if (response && (ret == BT_SUCCESS)) + { + sem_wait(&priv->api_sync); + ret = priv->result; + } + + return ret; +} + +int read_gatt_char(uint16_t handle, uint8_t *data, int *len) +{ + int ret; + struct ble_app_private_t *priv = &g_ble_app_priv; + + *len = 0; + + ret = ble_read_characteristic(g_connecthdl, handle); + if (ret == BT_SUCCESS) + { + sem_wait(&priv->api_sync); + ret = priv->result; + if (ret == 0) + { + *len = priv->len; + memcpy(data, priv->buffer, priv->len); + } + } + + return ret; +} + +int scan_filter_uuid(BLE_UUID *uuid) +{ + g_filter_uuid = *uuid; + return 0; +} + +int scan_filter_device_name(const char *name) +{ + strncpy(g_filter_devname, name, sizeof(g_filter_devname) - 1); + return 0; +} + +int register_discover(BLE_UUID *uuid, discover_cb_t cb) +{ + struct discover_node_s *node; + + node = malloc(sizeof(struct discover_node_s)); + if (!node) + { + return -ENOMEM; + } + + /* Insert into discover list. */ + + node->cb = cb; + node->uuid = *uuid; + node->nhandle = 0; + SLIST_INSERT_HEAD(&g_discover_list, node, entries); + + return 0; +} + +int unregister_discover(BLE_UUID *uuid) +{ + struct discover_node_s *node; + struct discover_node_s *tmp; + + /* Remove from discover list. */ + + SLIST_FOREACH_SAFE(node, &g_discover_list, entries, tmp) + { + if (0 == bleutil_uuidcmp(&node->uuid, uuid)) + { + SLIST_REMOVE(&g_discover_list, node, discover_node_s, entries); + free(node); + } + } + + return 0; +} + +int start_notify(BLE_UUID *uuid, notify_cb_t cb) +{ + int ret = 0; + uint16_t notify_en = 1; + struct notify_node_s *nnode; + struct discover_node_s *dnode; + int nhandle = 0; + int i; + uint16_t cccd_handle; + + /* Get the handle numbers from discovered UUID. */ + + SLIST_FOREACH(dnode, &g_discover_list, entries) + { + if (bleutil_uuidcmp(&dnode->uuid, uuid) == 0) + { + nhandle = dnode->nhandle; + break; + } + } + + if (nhandle == 0) + { + return -ENOENT; + } + + /* Insert into notify list. */ + + nnode = malloc(sizeof(struct notify_node_s)); + if (!nnode) + { + return -ENOMEM; + } + + nnode->cb = cb; + nnode->uuid = *uuid; + nnode->nhandle = nhandle; + memcpy(nnode->handles, dnode->handles, sizeof(nnode->handles)); + SLIST_INSERT_HEAD(&g_notify_list, nnode, entries); + + /* Enable notification on CCCD handle. */ + + for (i = 0; i < nhandle; i++) + { + cccd_handle = dnode->handles[i].cccd_handle; + if (cccd_handle != BLE_GATT_INVALID_ATTRIBUTE_HANDLE) + { + ret = write_gatt_descriptor(cccd_handle, + (uint8_t *)¬ify_en, sizeof(notify_en)); + if (ret != BT_SUCCESS) + { + printf("ERROR: Failed to enable notification ret=%d\n", ret); + } + } + } + + return ret; +} + +int stop_notify(BLE_UUID *uuid) +{ + int ret = 0; + uint16_t notify_en = 0; + struct notify_node_s *node; + struct notify_node_s *tmp; + int i; + uint16_t cccd_handle; + + /* Remove from notify list. */ + + SLIST_FOREACH_SAFE(node, &g_notify_list, entries, tmp) + { + if (bleutil_uuidcmp(&node->uuid, uuid) == 0) + { + for (i = 0; i < node->nhandle; i++) + { + cccd_handle = node->handles[i].cccd_handle; + if (cccd_handle != BLE_GATT_INVALID_ATTRIBUTE_HANDLE) + { + ret = write_gatt_descriptor(cccd_handle, + (uint8_t *)¬ify_en, sizeof(notify_en)); + } + } + + SLIST_REMOVE(&g_notify_list, node, notify_node_s, entries); + free(node); + } + } + + return ret; +} + +int ble_app_init(void) +{ + int ret = 0; + struct ble_app_private_t *priv = &g_ble_app_priv; + + /* Initialize private data. */ + + sem_init(&priv->event_sync, 0, 0); + sem_init(&priv->api_sync, 0, 0); + + memset(g_filter_devname, 0, sizeof(g_filter_devname)); + + /* Initialize BT/BLE */ + + bt_init(); + + ble_register_common_cb(&ble_common_ops); + ble_register_gatt_central_cb(&ble_central_ops); + + return ret; +} + +enum ble_app_event ble_app_wait_event(void) +{ + struct ble_app_private_t *priv = &g_ble_app_priv; + + sem_wait(&priv->event_sync); + return priv->event; +} diff --git a/examples/ble_toio_central/ble_central_app.h b/examples/ble_toio_central/ble_central_app.h new file mode 100644 index 000000000..ece79a26e --- /dev/null +++ b/examples/ble_toio_central/ble_central_app.h @@ -0,0 +1,131 @@ +/**************************************************************************** + * examples/ble_toio_central/ble_central_app.h + * + * Copyright 2024 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __EXAMPLES_BLE_TOIO_CENTRAL_BLE_CENTRAL_APP_H +#define __EXAMPLES_BLE_TOIO_CENTRAL_BLE_CENTRAL_APP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define BLE_UUID16(_uuid) \ +{ \ + .type = BLE_UUID_TYPE_BASEALIAS_BTSIG, \ + .value.alias.uuidAlias = _uuid, \ +} + +#define BLE_UUID128(_uuid) \ +{ \ + .type = BLE_UUID_TYPE_UUID128, \ + .value.uuid128 = {_uuid}, \ +} + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* BLE app event */ + +enum ble_app_event +{ + BLE_APP_CONNECTED, + BLE_APP_DISCONNECTED, +}; + +/* Discovery callback */ + +typedef void (*discover_cb_t)(struct ble_gattc_db_disc_char_s *gatt_disc_char); + +/* Notify callback */ + +typedef void (*notify_cb_t)(struct ble_gatt_char_s *gatt_char); + +/**************************************************************************** + * Public Functions Prototype + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/* BLE GATT synchronous API + * These APIs can be called only from application threads. + * They must not be called from notify callback threads. + */ + +int write_gatt_descriptor(uint16_t handle, uint8_t *data, int len); +int read_gatt_descriptor(uint16_t handle, uint8_t *data, int *len); +int write_gatt_char(uint16_t handle, uint8_t *data, int len, bool response); +int read_gatt_char(uint16_t handle, uint8_t *data, int *len); + +/* BLE Scan filter API */ + +int scan_filter_uuid(BLE_UUID *uuid); +int scan_filter_device_name(const char *name); + +/* BLE Register discovery API */ + +int register_discover(BLE_UUID *uuid, discover_cb_t cb); +int unregister_discover(BLE_UUID *uuid); + +/* BLE Notify API */ + +int start_notify(BLE_UUID *uuid, notify_cb_t cb); +int stop_notify(BLE_UUID *uuid); + +/* BLE App API */ + +int ble_app_init(void); +enum ble_app_event ble_app_wait_event(void); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __EXAMPLES_BLE_TOIO_CENTRAL_BLE_CENTRAL_APP_H */ diff --git a/examples/ble_toio_central/ble_toio_central_main.cxx b/examples/ble_toio_central/ble_toio_central_main.cxx new file mode 100644 index 000000000..a9975a066 --- /dev/null +++ b/examples/ble_toio_central/ble_toio_central_main.cxx @@ -0,0 +1,365 @@ +/**************************************************************************** + * examples/ble_toio_central/ble_toio_central_main.cxx + * + * Copyright 2024 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ble_central_app.h" +#include "toio.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* toio: Service UUID */ + +const char *SERVICE_UUID = "10B20100-5B3B-4571-9508-CF3EFCD7BBAE"; + +/* toio: Characteristic UUID */ + +const char *ID_UUID = "10B20101-5B3B-4571-9508-CF3EFCD7BBAE"; +const char *MOTOR_UUID = "10B20102-5B3B-4571-9508-CF3EFCD7BBAE"; +const char *LIGHT_UUID = "10B20103-5B3B-4571-9508-CF3EFCD7BBAE"; +const char *SOUND_UUID = "10B20104-5B3B-4571-9508-CF3EFCD7BBAE"; +const char *SENSOR_UUID = "10B20106-5B3B-4571-9508-CF3EFCD7BBAE"; +const char *BUTTON_UUID = "10B20107-5B3B-4571-9508-CF3EFCD7BBAE"; +const char *BATTERY_UUID = "10B20108-5B3B-4571-9508-CF3EFCD7BBAE"; +const char *SETTING_UUID = "10B201FF-5B3B-4571-9508-CF3EFCD7BBAE"; + +/* Characteristic UUIDs */ + +static BLE_UUID g_id_uuid; +static BLE_UUID g_motor_uuid; +static BLE_UUID g_light_uuid; +static BLE_UUID g_sound_uuid; +static BLE_UUID g_sensor_uuid; +static BLE_UUID g_button_uuid; +static BLE_UUID g_battery_uuid; +static BLE_UUID g_setting_uuid; + +/* Characteristic handles */ + +static uint16_t g_id_handle; +static uint16_t g_motor_handle; +static uint16_t g_light_handle; +static uint16_t g_sound_handle; +static uint16_t g_sensor_handle; +static uint16_t g_button_handle; +static uint16_t g_battery_handle; +static uint16_t g_setting_handle; + +static volatile bool g_thread_finished; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* Get characteristic handle of the discovered UUID */ + +static void char_discovered(struct ble_gattc_db_disc_char_s *gatt_disc_char) +{ + struct ble_gattc_char_s *ch = &gatt_disc_char->characteristic; + + printf("%s()\n", __func__); + + if (bleutil_uuidcmp(&g_id_uuid, &ch->char_valuuid) == 0) + { + g_id_handle = ch->char_valhandle; + } + + if (bleutil_uuidcmp(&g_motor_uuid, &ch->char_valuuid) == 0) + { + g_motor_handle = ch->char_valhandle; + } + + if (bleutil_uuidcmp(&g_light_uuid, &ch->char_valuuid) == 0) + { + g_light_handle = ch->char_valhandle; + } + + if (bleutil_uuidcmp(&g_sound_uuid, &ch->char_valuuid) == 0) + { + g_sound_handle = ch->char_valhandle; + } + + if (bleutil_uuidcmp(&g_sensor_uuid, &ch->char_valuuid) == 0) + { + g_sensor_handle = ch->char_valhandle; + } + + if (bleutil_uuidcmp(&g_button_uuid, &ch->char_valuuid) == 0) + { + g_button_handle = ch->char_valhandle; + } + + if (bleutil_uuidcmp(&g_battery_uuid, &ch->char_valuuid) == 0) + { + g_battery_handle = ch->char_valhandle; + } + + if (bleutil_uuidcmp(&g_setting_uuid, &ch->char_valuuid) == 0) + { + g_setting_handle = ch->char_valhandle; + } +} + +/**************************************************************************** + * toio_thread_main + ****************************************************************************/ + +static void *toio_thread_main(void *arg) +{ + Identification id(g_id_handle); + Motor motor(g_motor_handle); + Light light(g_light_handle); + Sound sound(g_sound_handle); + Sensor sensor(g_sensor_handle); + Button button(g_button_handle); + Battery battery(g_battery_handle); + Setting setting(g_setting_handle); + + bool mat = false; + + printf("Protocol version: %s\n", setting.version()); + printf("Battery level: %d %%\n", battery.level()); + + printf("Play sound effect: Enter\n"); + sound.play_sound_effect(Sound::Enter); + + printf("Motor spin\n"); + motor.run(100, -100, 100); + sleep(1); + motor.run(-100, 100, 100); + sleep(1); + + while (!g_thread_finished) + { + if (sensor.tilt_detected()) + { + printf("Motion: Tilt detected!!\n"); + printf("Turn on light: Blue\n"); + light.on(0, 0, 255); + printf("Play sound effect: Get1\n"); + sound.play_sound_effect(Sound::Get1); + } + + if (sensor.collision_detected()) + { + printf("Motion: Collision detected!!\n"); + printf("Turn on light: Red:\n"); + light.on(255, 0, 0); + printf("Play sound effect: Get2\n"); + sound.play_sound_effect(Sound::Get2); + } + + if (sensor.shake_detected()) + { + printf("Motion: Shake detected!!\n"); + printf("Turn on light: Green\n"); + light.on(0, 255, 0); + printf("Play sound effect: Get3\n"); + sound.play_sound_effect(Sound::Get3); + } + + if (button.is_pressed()) + { + printf("Battery level: %d %%\n", battery.level()); + printf("Turn off light\n"); + light.off(); + } + + if (!mat && (id.is_valid_position() || id.is_valid_standard())) + { + /* In the mat for the first time. */ + + mat = true; + printf("Play sound effect: MatIn\n"); + sound.play_sound_effect(Sound::MatIn); + if (id.is_valid_position()) + { + printf("(x, y, angle) = (%4d, %4d, %3d)\n", id.x(), id.y(), id.angle()); + } + if (id.is_valid_standard()) + { + printf("(stadard, angle) = (0x%08lx, %3d)\n", id.value(), id.angle()); + } + } + + if (mat && (!id.is_valid_position() && !id.is_valid_standard())) + { + /* Out of the mat. */ + + mat = false; + printf("Play sound effect: MatOut\n"); + sound.play_sound_effect(Sound::MatOut); + } + + /* Yield periodically to dispatch to other threads. */ + + usleep(1); + } + + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +extern "C" int main(int argc, FAR char *argv[]) +{ + int ret; + char myname[] = "BLE_TOIO_CENTRAL"; + BT_ADDR myaddr = {{0x19, 0x84, 0x06, 0x14, 0xAB, 0xCD}}; + BLE_UUID service_uuid; + pthread_t toio_thread; + + /* Convert UUID strings to BLE_UUID value. */ + + bleutil_convert_str2uuid(const_cast(SERVICE_UUID), &service_uuid); + bleutil_convert_str2uuid(const_cast(ID_UUID), &g_id_uuid); + bleutil_convert_str2uuid(const_cast(MOTOR_UUID), &g_motor_uuid); + bleutil_convert_str2uuid(const_cast(LIGHT_UUID), &g_light_uuid); + bleutil_convert_str2uuid(const_cast(SOUND_UUID), &g_sound_uuid); + bleutil_convert_str2uuid(const_cast(SENSOR_UUID), &g_sensor_uuid); + bleutil_convert_str2uuid(const_cast(BUTTON_UUID), &g_button_uuid); + bleutil_convert_str2uuid(const_cast(BATTERY_UUID), &g_battery_uuid); + bleutil_convert_str2uuid(const_cast(SETTING_UUID), &g_setting_uuid); + + /* Initialize BLE central application. */ + + ble_app_init(); + + ble_set_name(myname); + ble_set_address(&myaddr); + + ret = bt_enable(); + if (ret != BT_SUCCESS) + { + printf("ERROR: bt_enable() ret=%d\n", ret); + return ret; + } + + ret = ble_enable(); + if (ret != BT_SUCCESS) + { + printf("ERROR: ble_enable() ret=%d\n", ret); + goto error; + } + + /* Allow the vendor specific UUIDs to be discovered. */ + + ble_set_vendor_uuid(&service_uuid); + + /* Set scan filter to connect if the specified UUID is found. */ + + scan_filter_uuid(&service_uuid); + + /*scan_filter_device_name("toio-xxx");*/ + + /* Discover characteristic to get the handle. */ + + register_discover(&g_id_uuid, char_discovered); + register_discover(&g_motor_uuid, char_discovered); + register_discover(&g_light_uuid, char_discovered); + register_discover(&g_sound_uuid, char_discovered); + register_discover(&g_sensor_uuid, char_discovered); + register_discover(&g_button_uuid, char_discovered); + register_discover(&g_battery_uuid, char_discovered); + register_discover(&g_setting_uuid, char_discovered); + + ret = ble_start_scan(false); + if (ret != BT_SUCCESS) + { + printf("[%s] ble_start_scan() failed. ret = %d\n", __func__, ret); + goto error; + } + + while (1) + { + switch (ble_app_wait_event()) + { + case BLE_APP_CONNECTED: + g_thread_finished = false; + ret = pthread_create(&toio_thread, NULL, toio_thread_main, NULL); + if (ret != 0) + { + printf("ERROR: pthread_create() failed: %d\n", ret); + goto error; + } + break; + case BLE_APP_DISCONNECTED: + printf("Finish application.\n"); + g_thread_finished = true; + pthread_join(toio_thread, NULL); + goto error; + break; + default: + break; + } + } + +error: + /* Unregister discover callbacks. */ + + unregister_discover(&g_id_uuid); + unregister_discover(&g_motor_uuid); + unregister_discover(&g_light_uuid); + unregister_discover(&g_sound_uuid); + unregister_discover(&g_sensor_uuid); + unregister_discover(&g_button_uuid); + unregister_discover(&g_battery_uuid); + unregister_discover(&g_setting_uuid); + + ble_disable(); + bt_disable(); + + return ret; +} diff --git a/examples/ble_toio_central/toio.h b/examples/ble_toio_central/toio.h new file mode 100644 index 000000000..b1220f968 --- /dev/null +++ b/examples/ble_toio_central/toio.h @@ -0,0 +1,617 @@ +/**************************************************************************** + * examples/ble_toio_central/toio.h + * + * Copyright 2024 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __EXAMPLES_BLE_TOIO_CENTRAL_TOIO_H +#define __EXAMPLES_BLE_TOIO_CENTRAL_TOIO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ble_central_app.h" + +/**************************************************************************** + * Public Classes + ****************************************************************************/ + +/**************************************************************************** + * Identification + ****************************************************************************/ + +class Identification +{ + public: + Identification(uint16_t handle) : m_handle(handle) + { + start_notify(const_cast(&s_uuid), Identification::notify); + } + + ~Identification() + { + stop_notify(const_cast(&s_uuid)); + } + + struct id_s + { + uint16_t x; + uint16_t y; + uint16_t angle; + uint16_t sensor_x; + uint16_t sensor_y; + uint16_t sensor_angle; + uint32_t value; + bool valid_position; + bool valid_standard; + }; + + static struct id_s s_id; + + static void notify(struct ble_gatt_char_s *gatt_char) + { + begin_packed_struct struct position_id_s + { + uint8_t type; + uint16_t x; + uint16_t y; + uint16_t angle; + uint16_t sensor_x; + uint16_t sensor_y; + uint16_t sensor_angle; + } end_packed_struct *pos_id; + + begin_packed_struct struct standard_id_s + { + uint8_t type; + uint32_t value; + uint16_t angle; + } end_packed_struct *std_id; + + uint8_t type; + + type = gatt_char->value.data[0]; + + if (type == 0x01) + { + pos_id = (struct position_id_s *)gatt_char->value.data; + s_id.x = pos_id->x; + s_id.y = pos_id->y; + s_id.angle = pos_id->angle; + s_id.sensor_x = pos_id->sensor_x; + s_id.sensor_y = pos_id->sensor_y; + s_id.sensor_angle = pos_id->sensor_angle; + s_id.value = 0; + s_id.valid_position = true; + s_id.valid_standard = false; + } + else if (type == 0x02) + { + std_id = (struct standard_id_s *)gatt_char->value.data; + s_id.x = 0; + s_id.y = 0; + s_id.angle = std_id->angle; + s_id.sensor_x = 0; + s_id.sensor_y = 0; + s_id.sensor_angle = 0; + s_id.value = std_id->value; + s_id.valid_position = false; + s_id.valid_standard = true; + } + else if (type == 0x03) + { + //printf("Position ID missed\n"); + memset(&s_id, 0, sizeof(s_id)); + s_id.valid_position = false; + s_id.valid_standard = false; + } + else if (type == 0x04) + { + //printf("Standard ID missed\n"); + memset(&s_id, 0, sizeof(s_id)); + s_id.valid_position = false; + s_id.valid_standard = false; + } + } + + uint16_t x() { return s_id.x; } + uint16_t y() { return s_id.y; } + uint16_t angle() { return s_id.angle; } + uint16_t sensor_x() { return s_id.sensor_x; } + uint16_t sensor_y() { return s_id.sensor_y; } + uint16_t sensor_angle() { return s_id.sensor_angle; } + uint32_t value() { return s_id.value; } + bool is_valid_position() { return s_id.valid_position; } + bool is_valid_standard() { return s_id.valid_standard; } + + private: + static const BLE_UUID s_uuid; + uint16_t m_handle; +}; + +struct Identification::id_s Identification::s_id = { 0 }; +const BLE_UUID Identification::s_uuid = { BLE_UUID_TYPE_UUID128, + { 0xae, 0xbb, 0xd7, 0xfc, 0x3e, 0xcf, 0x08, 0x95, + 0x71, 0x45, 0x3b, 0x5b, 0x01, 0x01, 0xb2, 0x10 }}; + +/**************************************************************************** + * Motor + ****************************************************************************/ + +class Motor +{ + public: + Motor(uint16_t handle) : m_handle(handle) {} + ~Motor() {} + + int run(int8_t left_speed, int8_t right_speed, uint8_t duration = 0) + { + int ret; + struct motor_control_t + { + uint8_t type; + uint8_t left_id; + uint8_t left_direction; + uint8_t left_speed; + uint8_t right_id; + uint8_t right_direction; + uint8_t right_speed; + uint8_t duration; /* Actual period: duration x10 [msec] */ + } control = + { + .type = 0x02, + .left_id = 0x01, + .left_direction = static_cast((left_speed > 0) ? 1 : 2), + .left_speed = static_cast(abs(left_speed)), + .right_id = 0x02, + .right_direction = static_cast((right_speed > 0) ? 1 : 2), + .right_speed = static_cast(abs(right_speed)), + .duration = duration, + }; + + ret = write_gatt_char(m_handle, (uint8_t *)&control, sizeof(control), false); + if (ret != 0) + { + printf("ERROR: %s() write ret=%d\n", __func__, ret); + } + + return ret; + } + + int stop() + { + return run(0, 0); + } + + private: + static const BLE_UUID s_uuid; + uint16_t m_handle; +}; + +const BLE_UUID Motor::s_uuid = { BLE_UUID_TYPE_UUID128, + { 0xae, 0xbb, 0xd7, 0xfc, 0x3e, 0xcf, 0x08, 0x95, + 0x71, 0x45, 0x3b, 0x5b, 0x02, 0x01, 0xb2, 0x10 }}; + +/**************************************************************************** + * Light + ****************************************************************************/ + +class Light +{ + public: + Light(uint16_t handle) : m_handle(handle) {} + ~Light() {} + + int on(uint8_t red, uint8_t green, uint8_t blue, uint8_t duration = 0) + { + int ret; + struct lamp_control_t + { + uint8_t type; + uint8_t duration; + uint8_t num; + uint8_t id; + uint8_t red; + uint8_t green; + uint8_t blue; + } control = + { + .type = 0x03, + .duration = duration, /* Actual period: duration x10 [msec] */ + .num = 0x01, + .id = 0x01, + .red = red, + .green = green, + .blue = blue, + }; + + ret = write_gatt_char(m_handle, (uint8_t *)&control, sizeof(control), true); + if (ret != 0) + { + printf("ERROR: %s() write ret=%d\n", __func__, ret); + } + + return ret; + } + + int off(void) + { + int ret; + uint8_t control = 0x01; + + ret = write_gatt_char(m_handle, (uint8_t *)&control, sizeof(control), true); + if (ret != 0) + { + printf("ERROR: %s() write ret=%d\n", __func__, ret); + } + + return ret; + } + + private: + static const BLE_UUID s_uuid; + uint16_t m_handle; +}; + +const BLE_UUID Light::s_uuid = { BLE_UUID_TYPE_UUID128, + { 0xae, 0xbb, 0xd7, 0xfc, 0x3e, 0xcf, 0x08, 0x95, + 0x71, 0x45, 0x3b, 0x5b, 0x03, 0x01, 0xb2, 0x10 }}; + +/**************************************************************************** + * Sound + ****************************************************************************/ + +class Sound +{ + public: + Sound(uint16_t handle) : m_handle(handle) {} + ~Sound() {} + + enum EffectID + { + Enter = 0, + Selected, + Cancel, + Cursor, + MatIn, + MatOut, + Get1, + Get2, + Get3, + Effect1, + Effect2, + }; + + int play_sound_effect(EffectID id) + { + int ret; + uint8_t control[] = { 0x02, static_cast(id), 0x01 }; + + ret = write_gatt_char(m_handle, (uint8_t *)&control, sizeof(control), true); + if (ret != 0) + { + printf("ERROR: %s() write ret=%d\n", __func__, ret); + } + + return ret; + } + + int stop() + { + int ret; + uint8_t control = 0x01; + + ret = write_gatt_char(m_handle, (uint8_t *)&control, sizeof(control), true); + if (ret != 0) + { + printf("ERROR: %s() write ret=%d\n", __func__, ret); + } + + return ret; + } + + private: + static const BLE_UUID s_uuid; + uint16_t m_handle; +}; + +const BLE_UUID Sound::s_uuid = { BLE_UUID_TYPE_UUID128, + { 0xae, 0xbb, 0xd7, 0xfc, 0x3e, 0xcf, 0x08, 0x95, + 0x71, 0x45, 0x3b, 0x5b, 0x04, 0x01, 0xb2, 0x10 }}; + +/**************************************************************************** + * Sensor + ****************************************************************************/ + +class Sensor +{ + public: + Sensor(uint16_t handle) : m_handle(handle) + { + start_notify(const_cast(&s_uuid), Sensor::notify); + } + + ~Sensor() + { + stop_notify(const_cast(&s_uuid)); + } + + static uint8_t s_motion; + + static void notify(struct ble_gatt_char_s *gatt_char) + { + struct motion_data_t + { + uint8_t type; + uint8_t tilt; + uint8_t collision; + uint8_t double_tap; + uint8_t posture; + uint8_t shake; + } *data; + + data = (struct motion_data_t *)gatt_char->value.data; + + if (data->type == 0x01) + { + if (data->tilt == 0x00) + { + //printf("Motion: Tilt\n"); + s_motion |= FLAG_TILT; + } + if (data->collision == 0x01) + { + //printf("Motion: Collision\n"); + s_motion |= FLAG_COLLISTION; + } + if (data->double_tap == 0x01) + { + //printf("Motion: Double-Tap\n"); + s_motion |= FLAG_DOUBLE_TAP; + } + if (data->shake > 0x00) + { + //printf("Motion: Shake\n"); + s_motion |= FLAG_SHAKE; + } + s_motion &= ~FLAG_POSTURE; + s_motion |= (data->posture & FLAG_POSTURE); + } + } + + bool tilt_detected() + { + bool detected = (s_motion & FLAG_TILT); + s_motion &= ~FLAG_TILT; + return detected; + } + + bool collision_detected() + { + bool detected = (s_motion & FLAG_COLLISTION); + s_motion &= ~FLAG_COLLISTION; + return detected; + } + + bool double_tap_detected() + { + bool detected = (s_motion & FLAG_DOUBLE_TAP); + s_motion &= ~FLAG_DOUBLE_TAP; + return detected; + } + + bool shake_detected() + { + bool detected = (s_motion & FLAG_SHAKE); + s_motion &= ~FLAG_SHAKE; + return detected; + } + + uint8_t posture() + { + return (s_motion & FLAG_POSTURE); + } + + private: + enum Flags + { + FLAG_POSTURE = 0xf, + FLAG_TILT = 1 << 4, + FLAG_COLLISTION = 1 << 5, + FLAG_DOUBLE_TAP = 1 << 6, + FLAG_SHAKE = 1 << 7, + }; + + private: + static const BLE_UUID s_uuid; + uint16_t m_handle; +}; + +uint8_t Sensor::s_motion = 0; +const BLE_UUID Sensor::s_uuid = { BLE_UUID_TYPE_UUID128, + { 0xae, 0xbb, 0xd7, 0xfc, 0x3e, 0xcf, 0x08, 0x95, + 0x71, 0x45, 0x3b, 0x5b, 0x06, 0x01, 0xb2, 0x10 }}; + +/**************************************************************************** + * Button + ****************************************************************************/ + +class Button +{ + public: + Button(uint16_t handle) : m_handle(handle) + { + start_notify(const_cast(&s_uuid), Button::notify); + } + + ~Button() + { + stop_notify(const_cast(&s_uuid)); + } + + static uint8_t s_state; + + static void notify(struct ble_gatt_char_s *gatt_char) + { + struct button_data_t + { + uint8_t id; + uint8_t state; + } *data; + + data = (struct button_data_t *)gatt_char->value.data; + + if (data->id == 0x01) + { + //printf("Button: %s\n", (data->state == 0x80) ? "Pushed" : "Released"); + s_state = data->state; + } + } + + bool is_pressed() + { + return (s_state == 0x80); + } + + bool is_released() + { + return (s_state != 0x80); + } + + private: + static const BLE_UUID s_uuid; + uint16_t m_handle; +}; + +uint8_t Button::s_state = 0; +const BLE_UUID Button::s_uuid = { BLE_UUID_TYPE_UUID128, + { 0xae, 0xbb, 0xd7, 0xfc, 0x3e, 0xcf, 0x08, 0x95, + 0x71, 0x45, 0x3b, 0x5b, 0x07, 0x01, 0xb2, 0x10 }}; + +/**************************************************************************** + * Battery + ****************************************************************************/ + +class Battery +{ + public: + Battery(uint16_t handle) : m_handle(handle) {} + ~Battery() {} + + uint8_t level() + { + int ret; + int len; + uint8_t level = 0; + + ret = read_gatt_char(m_handle, &level, &len); + if (ret != 0) + { + printf("ERROR: %s() read ret=%d\n", __func__, ret); + } + + return level; + } + + private: + static const BLE_UUID s_uuid; + uint16_t m_handle; +}; + +const BLE_UUID Battery::s_uuid = { BLE_UUID_TYPE_UUID128, + { 0xae, 0xbb, 0xd7, 0xfc, 0x3e, 0xcf, 0x08, 0x95, + 0x71, 0x45, 0x3b, 0x5b, 0x08, 0x01, 0xb2, 0x10 }}; + +/**************************************************************************** + * Settings + ****************************************************************************/ + +class Setting +{ + public: + Setting(uint16_t handle) : m_handle(handle) {} + ~Setting() {} + + const char *version() + { + int ret; + int len; + struct verinfo_s + { + uint8_t type; + uint8_t reserved; + char version[6]; + } verinfo = { + .type = 0x01, + .reserved = 0x00, + }; + + memset(verinfo.version, 0, sizeof(verinfo.version)); + + ret = write_gatt_char(m_handle, (uint8_t *)&verinfo, 2, true); + if (ret != 0) + { + printf("ERROR: %s() write ret=%d\n", __func__, ret); + } + + ret = read_gatt_char(m_handle, (uint8_t *)&verinfo, &len); + if (ret != 0) + { + printf("ERROR: %s() read ret=%d\n", __func__, ret); + } + + strncpy(m_version, verinfo.version, sizeof(m_version)); + return m_version; + } + + private: + char m_version[6]; + static const BLE_UUID s_uuid; + uint16_t m_handle; +}; + +const BLE_UUID Setting::s_uuid = { BLE_UUID_TYPE_UUID128, + { 0xae, 0xbb, 0xd7, 0xfc, 0x3e, 0xcf, 0x08, 0x95, + 0x71, 0x45, 0x3b, 0x5b, 0xff, 0x01, 0xb2, 0x10 }}; + +#endif /* __EXAMPLES_BLE_TOIO_CENTRAL_TOIO_H */ diff --git a/examples/bluetooth_le_central/README.txt b/examples/bluetooth_le_central/README.txt index d163ca5b5..4b70c5e3e 100644 --- a/examples/bluetooth_le_central/README.txt +++ b/examples/bluetooth_le_central/README.txt @@ -21,6 +21,15 @@ examples/bluetooth_le_central 1. Launch "ble_central" application by NuttShell $ ble_central + If there is only one argument, you are able to specify a device name. + $ ble_central + is a string. + + If there are two arguments, you are able to specify service and characteristic UUIDs. + $ ble_central + is a hexadecimal string without "0x". + e.g.) 1812, 12345678-90AB-CDEF-1234-567890ABCDEF + 2. Then, the following BLE procedures are executed automatically. - scan and connect to peripheral device named "SONY-PERIPHERAL" (e.g. /examples/bluetooth_le_peripheral/ application.) diff --git a/examples/bluetooth_le_central/bluetooth_le_central_main.c b/examples/bluetooth_le_central/bluetooth_le_central_main.c index 7ed5c0d59..61820093f 100644 --- a/examples/bluetooth_le_central/bluetooth_le_central_main.c +++ b/examples/bluetooth_le_central/bluetooth_le_central_main.c @@ -1,7 +1,7 @@ /**************************************************************************** * bluetooth_le_central/bluetooth_le_central_main.c * - * Copyright 2018, 2022 Sony Semiconductor Solutions Corporation + * Copyright 2018, 2022, 2024 Sony Semiconductor Solutions Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -159,6 +159,7 @@ static struct ble_cccd_s **g_cccd = NULL; static bool g_target = false; static BLE_UUID g_target_srv_uuid; static BLE_UUID g_target_char_uuid; +static char g_target_device_name[BT_NAME_LEN] = "SONY-PERIPHERAL"; static uint8_t g_read_data[BLE_MAX_GATT_DATA_LEN]; static uint16_t g_read_datalen; @@ -193,7 +194,7 @@ static void on_le_connect_status_change(struct ble_state_s *ble_state, printf(" : Cause <%s> :\n", cause == BLESTAT_SUCCESS ? "Success" : cause == BLESTAT_MEMCAP_EXCD ? "Mem capacity exceed" : - cause == BLESTAT_CONNECT_TIMEOUT ? "Connetion timeout" : + cause == BLESTAT_CONNECT_TIMEOUT ? "Connection timeout" : cause == BLESTAT_PEER_TERMINATED ? "Peripheral terminated" : cause == BLESTAT_PEER_TERM_LOWRES ? "Peripheral low resource" : cause == BLESTAT_PEER_TERM_POFF ? "Peripheral power off" : @@ -220,9 +221,10 @@ static void on_scan_result(BT_ADDR addr, uint8_t *data, uint8_t len) char devname[BT_EIR_LEN]; devname[0] = '\0'; - printf("[BLE] Scan result ADDR:%02X:%02X:%02X:%02X:%02X:%02X\n", + printf("[BLE] Scan result ADDR:%02X:%02X:%02X:%02X:%02X:%02X (RSSI:%ddB)\n", addr.address[5], addr.address[4], addr.address[3], - addr.address[2], addr.address[1], addr.address[0]); + addr.address[2], addr.address[1], addr.address[0], + bleutil_get_rssi(data, len)); /* If peer device has the device name, print it. */ @@ -246,12 +248,10 @@ static void on_scan_result(BT_ADDR addr, uint8_t *data, uint8_t len) } else { - const char target_device_name[] = "SONY-PERIPHERAL"; - - if (strcmp((char *)devname, target_device_name) != 0) + if (strcmp((char *)devname, g_target_device_name) != 0) { printf("%s [BLE] DevName is not matched: %s expect: %s\n", - __func__, devname, target_device_name); + __func__, devname, g_target_device_name); goto bye; } } @@ -456,7 +456,7 @@ static void on_read(uint16_t conn_handle, struct ble_gatt_char_s *ble_gatt_char) g_read_datalen = ble_gatt_char->value.length; memcpy(g_read_data, ble_gatt_char->value.data, g_read_datalen); - g_charrd_result = ble_gatt_char->status; + g_charrd_result = (g_read_datalen > 0) ? BT_SUCCESS : BT_FAIL; } static void on_notify(uint16_t conn_handle, struct ble_gatt_char_s *ble_gatt_char) @@ -500,6 +500,14 @@ static void on_db_discovery(struct ble_gatt_event_db_discovery_t *db_disc) db = &db_disc->params.db_discovery; srv = &db->services[0]; + /* If any error occurs, finish discovery */ + + if (db_disc->result != BT_SUCCESS) + { + printf("Discovery failed result=%d\n", db_disc->result); + goto finish; + } + for (i = 0; i < db->srv_count; i++, srv++) { printf("=== SRV[%d] ===\n", i); @@ -550,10 +558,11 @@ static void on_db_discovery(struct ble_gatt_event_db_discovery_t *db_disc) } /* The end_handle of the last service is 0xFFFF. - * So, if end_handle is not 0xFFFF, the continuous service information exists. + * When end_handle is 0x0000, no more services are found. + * So, if end_handle is not 0xFFFF or 0x0000, the continuous service information exists. */ - if (db_disc->state.end_handle != 0xFFFF) + if ((db_disc->state.end_handle != 0xFFFF) && (db_disc->state.end_handle != 0x0000)) { if (g_target == false) { @@ -563,6 +572,7 @@ static void on_db_discovery(struct ble_gatt_event_db_discovery_t *db_disc) } } +finish: g_discovered = true; } @@ -644,6 +654,12 @@ static int parse_argument(int argc, FAR char *argv[]) g_target = true; } + else if (argc == 2) + { + strncpy(g_target_device_name, argv[1], BT_NAME_LEN); + g_target_device_name[BT_NAME_LEN - 1] = '\0'; + g_target = false; + } else { g_target = false; @@ -822,21 +838,21 @@ static int access_descriptor(uint16_t conn_handle, struct ble_gattc_db_disc_char_s *char_db) { int ret = BT_SUCCESS; - uint16_t buf; - uint16_t len; + uint16_t buf = 0; + uint16_t len = 0; if (char_db->cccd_handle != BLE_GATT_INVALID_ATTRIBUTE_HANDLE) { ret = read_descriptor(conn_handle, char_db->cccd_handle, (uint8_t *)&buf, &len); - if (buf == NOTIFICATION_DISABLED) + if (ret != BT_SUCCESS) { - buf = NOTIFICATION_ENABLED; - ret = write_descriptor(conn_handle, char_db->cccd_handle, (uint8_t *)&buf, len); + return ret; } - if (ret != BT_SUCCESS) + if (buf == NOTIFICATION_DISABLED) { - return ret; + buf = NOTIFICATION_ENABLED; + ret = write_descriptor(conn_handle, char_db->cccd_handle, (uint8_t *)&buf, len); } } diff --git a/examples/bluetooth_spp/Kconfig b/examples/bluetooth_spp/Kconfig index 63b8c98f6..766f43cde 100644 --- a/examples/bluetooth_spp/Kconfig +++ b/examples/bluetooth_spp/Kconfig @@ -24,6 +24,6 @@ config EXAMPLES_BLUETOOTH_SPP_PRIORITY config EXAMPLES_BLUETOOTH_SPP_STACKSIZE int "Stack size" - default 2560 + default 4096 endif diff --git a/examples/eltres_lpwa/main_LPWA_sample_app.c b/examples/eltres_lpwa/main_LPWA_sample_app.c index 0503d963d..007712048 100644 --- a/examples/eltres_lpwa/main_LPWA_sample_app.c +++ b/examples/eltres_lpwa/main_LPWA_sample_app.c @@ -760,6 +760,7 @@ static uint32_t get_current_tm(void){ // Convert the number of seconds elapsed since GPS reference date and time obtained by above API to the number of seconds elapsed since 00:00:00 on January 1, 1900 // Convert by adding the number of seconds elapsed from 00:00:00 on January 1, 1900 to 00:00:00 on January 6, 1980, which is the base date of GPS time struct tm base_time; + memset(&base_time, 0, sizeof(base_time)); base_time.tm_sec = GPS_FORMAT_BASE_TIME_SEC; base_time.tm_min = GPS_FORMAT_BASE_TIME_MIN; base_time.tm_hour = GPS_FORMAT_BASE_TIME_HOUR; diff --git a/examples/gnss/Makefile b/examples/gnss/Makefile index de933ef32..43be0a9bd 100644 --- a/examples/gnss/Makefile +++ b/examples/gnss/Makefile @@ -45,6 +45,12 @@ MODULE = $(CONFIG_EXAMPLES_GNSS) # GNSS(simple) Example +ifneq ($(CONFIG_EXAMPLES_GNSS_USE_SIGNAL),) MAINSRC = gnss_main.c +endif + +ifneq ($(CONFIG_EXAMPLES_GNSS_USE_POLL),) +MAINSRC = gnss_poll_main.c +endif include $(APPDIR)/Application.mk diff --git a/examples/gnss/README.txt b/examples/gnss/README.txt index 0bf16e400..f396a96b6 100644 --- a/examples/gnss/README.txt +++ b/examples/gnss/README.txt @@ -22,8 +22,10 @@ examplex/gnss CONFIG_EXAMPLES_GNSS_STACKSIZE -- Specified this example's stack size. Default: 2048 CONFIGE_EXAMPLES_GNSS_USE_POLL -- Choice poll method event notification. + If choose this, gnss_poll_main.c is used. Default: CONFIGE_EXAMPLES_GNSS_USE_POLL - CONFIGE_EXAMPLES_GNSS_USE_SIGNAL -- Choice signal method event notification + CONFIGE_EXAMPLES_GNSS_USE_SIGNAL -- Choice signal method event notification. + If choose this, gnss_main.c is used. In addition to the above, the following definitions are required: CONFIG_CXD56_GNSS diff --git a/examples/gnss/gnss_main.c b/examples/gnss/gnss_main.c index 0692dff21..3f352cdc1 100644 --- a/examples/gnss/gnss_main.c +++ b/examples/gnss/gnss_main.c @@ -33,6 +33,10 @@ * ****************************************************************************/ +/* This example is showing how to use GNSS function on Spresense by using + * signal() method to wait result of measurement. + */ + /**************************************************************************** * Included Files ****************************************************************************/ diff --git a/examples/gnss/gnss_poll_main.c b/examples/gnss/gnss_poll_main.c new file mode 100644 index 000000000..ebf7cf09f --- /dev/null +++ b/examples/gnss/gnss_poll_main.c @@ -0,0 +1,367 @@ +/**************************************************************************** + * gnss/gnss_poll_main.c + * + * Copyright 2024 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/* This example is showing how to use GNSS function on Spresense by using + * poll() method to wait result of measurement. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct cxd56_gnss_dms_s +{ + int8_t sign; + uint8_t degree; + uint8_t minute; + uint32_t frac; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static uint32_t posfixflag; +static struct cxd56_gnss_positiondata_s posdat; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: double_to_dmf() + * + * Description: + * Convert from double format to degree-minute-frac format. + * + * Input Parameters: + * x - double value. + * dmf - Address to store the conversion result. + * + * Returned Value: + * none. + * + * Assumptions/Limitations: + * none. + * + ****************************************************************************/ + +static void double_to_dmf(double x, struct cxd56_gnss_dms_s * dmf) +{ + int b; + int d; + int m; + double f; + double t; + + if (x < 0) + { + b = 1; + x = -x; + } + else + { + b = 0; + } + d = (int)x; /* = floor(x), x is always positive */ + t = (x - d) * 60; + m = (int)t; /* = floor(t), t is always positive */ + f = (t - m) * 10000; + + dmf->sign = b; + dmf->degree = d; + dmf->minute = m; + dmf->frac = f; +} + +/**************************************************************************** + * Name: read_and_print() + * + * Description: + * Read and print POS data. + * + * Input Parameters: + * fd - File descriptor. + * + * Returned Value: + * Zero (OK) on success; Negative value on error. + * + * Assumptions/Limitations: + * none. + * + ****************************************************************************/ + +static int read_and_print(int fd) +{ + int ret; + struct cxd56_gnss_dms_s dmf; + + /* Read POS data. */ + + ret = read(fd, &posdat, sizeof(posdat)); + if (ret < 0) + { + printf("read error\n"); + goto _err; + } + else if (ret != sizeof(posdat)) + { + ret = ERROR; + printf("read size error\n"); + goto _err; + } + else + { + ret = OK; + } + + /* Print POS data. */ + + /* Print time. */ + + printf(">Hour:%d, minute:%d, sec:%d, usec:%ld\n", + posdat.receiver.time.hour, posdat.receiver.time.minute, + posdat.receiver.time.sec, posdat.receiver.time.usec); + if (posdat.receiver.pos_fixmode != CXD56_GNSS_PVT_POSFIX_INVALID) + { + /* 2D fix or 3D fix. + * Convert latitude and longitude into dmf format and print it. */ + + posfixflag = 1; + + double_to_dmf(posdat.receiver.latitude, &dmf); + printf(">LAT %d.%d.%04ld\n", dmf.degree, dmf.minute, dmf.frac); + + double_to_dmf(posdat.receiver.longitude, &dmf); + printf(">LNG %d.%d.%04ld\n", dmf.degree, dmf.minute, dmf.frac); + } + else + { + /* No measurement. */ + + printf(">No Positioning Data\n"); + } + +_err: + return ret; +} + +/**************************************************************************** + * Name: gnss_setparams() + * + * Description: + * Set gnss parameters use ioctl. + * + * Input Parameters: + * fd - File descriptor. + * + * Returned Value: + * Zero (OK) on success; Negative value on error. + * + * Assumptions/Limitations: + * none. + * + ****************************************************************************/ + +static int gnss_setparams(int fd) +{ + int ret = 0; + uint32_t set_satellite; + struct cxd56_gnss_ope_mode_param_s set_opemode; + + /* Set the GNSS operation interval. */ + + set_opemode.mode = 1; /* Operation mode:Normal(default). */ + set_opemode.cycle = 1000; /* Position notify cycle(msec step). */ + + ret = ioctl(fd, CXD56_GNSS_IOCTL_SET_OPE_MODE, (uint32_t)&set_opemode); + if (ret < 0) + { + printf("ioctl(CXD56_GNSS_IOCTL_SET_OPE_MODE) NG!!\n"); + goto _err; + } + + /* Set the type of satellite system used by GNSS. */ + + set_satellite = CXD56_GNSS_SAT_GPS | CXD56_GNSS_SAT_GLONASS; + + ret = ioctl(fd, CXD56_GNSS_IOCTL_SELECT_SATELLITE_SYSTEM, set_satellite); + if (ret < 0) + { + printf("ioctl(CXD56_GNSS_IOCTL_SELECT_SATELLITE_SYSTEM) NG!!\n"); + goto _err; + } + +_err: + return ret; +} + +/**************************************************************************** + * Name: gnss_main() + * + * Description: + * Set parameters and run positioning. + * + * Input Parameters: + * argc - Does not use. + * argv - Does not use. + * + * Returned Value: + * Zero (OK) on success; Negative value on error. + * + * Assumptions/Limitations: + * none. + * + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + int fd; + int ret; + int posperiod; + struct pollfd fds[1]; + + /* Program start. */ + + printf("Hello, GNSS <> SAMPLE!!\n"); + + /* Get file descriptor to control GNSS. */ + + fd = open(CONFIG_EXAMPLES_GNSS_DEVNAME, O_RDONLY); + if (fd < 0) + { + printf("open error:%d,%d\n", fd, errno); + return -ENODEV; + } + + /* Set GNSS parameters. */ + + ret = gnss_setparams(fd); + if (ret != OK) + { + printf("gnss_setparams failed. %d\n", ret); + goto _err; + } + + /* Initial positioning measurement becomes cold start if specified hot + * start, so working period should be long term to receive ephemeris. */ + + posperiod = 200; + posfixflag = 0; + + /* Start GNSS. */ + + ret = ioctl(fd, CXD56_GNSS_IOCTL_START, CXD56_GNSS_STMOD_HOT); + if (ret < 0) + { + printf("start GNSS ERROR %d\n", errno); + goto _err; + } + else + { + printf("start GNSS OK\n"); + } + + do + { + fds[0].fd = fd; + fds[0].events = POLLIN; + + /* Wait for positioning data to be notified. */ + + ret = poll(fds, 1, -1); + if (ret < 0) + { + printf("ERROR: poll ret=%d, errno=%d\n", ret, errno); + break; + } + + /* Read and print POS data. */ + + ret = read_and_print(fd); + if (ret < 0) + { + break; + } + + if (posfixflag) + { + /* Count down started after POS fixed. */ + + posperiod--; + } + } + while (posperiod > 0); + + /* Stop GNSS. */ + + ret = ioctl(fd, CXD56_GNSS_IOCTL_STOP, 0); + if (ret < 0) + { + printf("stop GNSS ERROR\n"); + } + else + { + printf("stop GNSS OK\n"); + } + +_err: + + /* Release GNSS file descriptor. */ + + ret = close(fd); + if (ret < 0) + { + printf("close error %d\n", errno); + } + + printf("End of GNSS Sample:%d\n", ret); + + return ret; +} diff --git a/examples/gnss_addon/gnss_addon_main.c b/examples/gnss_addon/gnss_addon_main.c index a6207995c..d73666854 100644 --- a/examples/gnss_addon/gnss_addon_main.c +++ b/examples/gnss_addon/gnss_addon_main.c @@ -264,6 +264,7 @@ static void set_datetime(struct cxd56_gnss_date_s *date, if (time->usec == 0) { + memset(&tm, 0, sizeof(tm)); tm.tm_year = date->year - 1900; tm.tm_mon = date->month - 1; tm.tm_mday = date->day; diff --git a/examples/lte_hibernation/lte_hibernation_main.c b/examples/lte_hibernation/lte_hibernation_main.c index 1b925414b..66d52091a 100644 --- a/examples/lte_hibernation/lte_hibernation_main.c +++ b/examples/lte_hibernation/lte_hibernation_main.c @@ -95,6 +95,25 @@ static char g_app_iobuffer[APP_IOBUFFER_LEN]; * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: get_file_size + * + * Description: + * Get the size of the specified file. + ****************************************************************************/ + +static int get_file_size(char *filename) +{ + struct stat tmp; + + if (stat(filename, &tmp) == 0) + { + return tmp.st_size; + } + + return -1; +} + /**************************************************************************** * Name: set_rtc_alarm * @@ -226,11 +245,11 @@ static int lte_enter_hibernation(void) static int lte_resume_from_hibernation(void) { - struct stat tmp; - uint8_t data[512] = {0}; int size = 0; + int ctx_size; int ret = 0; int fd = 0; + uint8_t data[64]; ret = lte_initialize(); if (ret < 0 && ret != -EALREADY) @@ -239,22 +258,50 @@ static int lte_resume_from_hibernation(void) return -1; } - if (stat(LTE_HIBERNATION_CONTEXT_PATH, &tmp) == 0) + size = get_file_size(LTE_HIBERNATION_CONTEXT_PATH); + if (size > 0) { - fd = open(LTE_HIBERNATION_CONTEXT_PATH, O_RDONLY); - size = read(fd, data, 512); - close(fd); + /* Get the context size required for resume. */ + + ctx_size = lte_hibernation_resume(NULL, 0); + if (ctx_size != size) + { + printf("File size does not match." + " file size = %d, context size = %d\n", + size, ctx_size); + ret = -1; + } + else + { + fd = open(LTE_HIBERNATION_CONTEXT_PATH, O_RDONLY); + + do + { + size = read(fd, data, sizeof(data)); + ret = lte_hibernation_resume(data, size); + if (ret < 0) + { + printf("lte_hibernation_resume failed.\n"); + } + else + { + printf("remain size = %d\n", ret); + } + } + while (ret > 0); + + close(fd); + } + unlink(LTE_HIBERNATION_CONTEXT_PATH); } else { - return -1; + ret = -1; } - ret = lte_hibernation_resume(data, size); - if (ret < 0) + if (ret != 0) { - printf("lte_hibernation_resume failed.\n"); lte_finalize(); return -1; } @@ -484,22 +531,29 @@ int main(int argc, FAR char *argv[]) printf("Resume from LTE hibernation mode.\n"); ret = lte_resume_from_hibernation(); - if (ret < 0) + if (ret == 0) { - return -1; + /* Run wget */ + + ret = perform_wget(); + if (ret < 0) + { + return -1; + } + + printf("End of this sample\n"); + return 0; } } - else - { - /* Normal boot */ - printf("Turn On LTE.\n"); + /* Normal boot */ - ret = app_connect_to_lte(&apnsetting); - if (ret < 0) - { - return -1; - } + printf("Turn On LTE.\n"); + + ret = app_connect_to_lte(&apnsetting); + if (ret < 0) + { + return -1; } /* Run wget */ @@ -531,6 +585,6 @@ int main(int argc, FAR char *argv[]) /* Entering cold sleep */ boardctl(BOARDIOC_POWEROFF, 1); - + return 0; } diff --git a/examples/lte_hibernation_wake_socket/file_utils.c b/examples/lte_hibernation_wake_socket/file_utils.c index 5671d75d2..f420b2ca3 100644 --- a/examples/lte_hibernation_wake_socket/file_utils.c +++ b/examples/lte_hibernation_wake_socket/file_utils.c @@ -132,3 +132,19 @@ bool app_file_exist(char *filename) return false; } + +/**************************************************************************** + * Name: app_file_size + ****************************************************************************/ + +int app_file_size(char *filename) +{ + struct stat tmp; + + if (stat(filename, &tmp) == 0) + { + return tmp.st_size; + } + + return 0; +} diff --git a/examples/lte_hibernation_wake_socket/file_utils.h b/examples/lte_hibernation_wake_socket/file_utils.h index 9d388cf0d..cd97e17b8 100644 --- a/examples/lte_hibernation_wake_socket/file_utils.h +++ b/examples/lte_hibernation_wake_socket/file_utils.h @@ -43,5 +43,6 @@ int app_save_file(FAR char *filename, FAR uint8_t *data, int size); int app_read_file(FAR char *filename, FAR uint8_t *data, int size); bool app_file_exist(char *filename); +int app_file_size(char *filename); #endif /* __EXAMPLES_LTE_HIBERNATION_WAKE_SOCKET_FILE_UTILS_H */ diff --git a/examples/lte_hibernation_wake_socket/lte_hibernation_wake_socket_main.c b/examples/lte_hibernation_wake_socket/lte_hibernation_wake_socket_main.c index c55af332f..3ad5d0fc3 100644 --- a/examples/lte_hibernation_wake_socket/lte_hibernation_wake_socket_main.c +++ b/examples/lte_hibernation_wake_socket/lte_hibernation_wake_socket_main.c @@ -211,8 +211,8 @@ static int load_sock_context(FAR char *filename) { int sockfd; struct socket_context_s sc; - int ret; - size_t size; + int ret = -1; + ssize_t size; FAR struct socket_ctx_data_s *sdata; size = app_read_file(filename, g_iobuffer, sizeof(g_iobuffer)); @@ -240,6 +240,7 @@ static int load_sock_context(FAR char *filename) if (ret < 0) { printf("SIOCSETCONTEXT failed:%d\n", errno); + close(sockfd); return -1; } @@ -394,8 +395,8 @@ static int save_tls_contexts(FAR struct wgetops_tls_context_s *ctx) static int load_tls_contexts(FAR struct wgetops_tls_context_s *ctx) { - size_t size; - int ret; + ssize_t size; + int ret = -1; /* Load context of mbedtls_net_context from file */ @@ -687,7 +688,10 @@ static int lte_enter_hibernation(void) static int lte_resume_from_hibernation(void) { int size = 0; + int ctx_size; int ret = 0; + int fd = 0; + uint8_t data[64]; if (strncmp(SD_MOUNT_POINT, SAVE_DIR, strlen(SD_MOUNT_POINT)) == 0) { @@ -705,23 +709,55 @@ static int lte_resume_from_hibernation(void) return -1; } - size = app_read_file(LTE_HIBERNATION_CONTEXT_PATH, - g_iobuffer, sizeof(g_iobuffer)); - if (size < 0) + size = app_file_size(LTE_HIBERNATION_CONTEXT_PATH); + if (size > 0) { - lte_finalize(); - return -1; + /* Get the context size required for resume. */ + + ctx_size = lte_hibernation_resume(NULL, 0); + if (ctx_size != size) + { + printf("File size does not match." + " file size = %d, context size = %d\n", + size, ctx_size); + ret = -1; + } + else + { + fd = open(LTE_HIBERNATION_CONTEXT_PATH, O_RDONLY); + + do + { + size = read(fd, data, sizeof(data)); + ret = lte_hibernation_resume(data, size); + if (ret < 0) + { + printf("lte_hibernation_resume failed.\n"); + } + else + { + printf("remain size = %d\n", ret); + } + } + while (ret > 0); + + close(fd); + } + + unlink(LTE_HIBERNATION_CONTEXT_PATH); + } + else + { + ret = -1; } - ret = lte_hibernation_resume(g_iobuffer, size); - if (ret < 0) + if (ret != 0) { - printf("lte_hibernation_resume failed.\n"); lte_finalize(); return -1; } - return ret; + return 0; } /**************************************************************************** @@ -895,7 +931,7 @@ int main(int argc, FAR char *argv[]) ret = lte_resume_from_hibernation(); if (ret < 0) { - return -1; + goto normal_boot; } /* Find out if there is a file that stores the context of the secure @@ -1000,71 +1036,73 @@ int main(int argc, FAR char *argv[]) printf("End of this sample\n"); } + + return 0; } - else - { - /* Normal boot */ - printf("Turn On LTE.\n"); +normal_boot: - /* ------------------------ - * 1. Connect LTE network - * ------------------------ - */ + /* Normal boot */ - ret = app_connect_to_lte(&apnsetting); - if (ret < 0) - { - return -1; - } + printf("Turn On LTE.\n"); - /* -------------------------------------- - * 2. send HTTP request (secure socket) - * -------------------------------------- - */ + /* ------------------------ + * 1. Connect LTE network + * ------------------------ + */ - /* HTTP requests are sent using secure socket. HTTP response will - * arrive 10 seconds later. In the meantime, Spresense sleeps and - * waits for the HTTP response, and wakes up when triggered by - * the HTTP response. - */ + ret = app_connect_to_lte(&apnsetting); + if (ret < 0) + { + return -1; + } - ret = send_https_request(&g_tls_context, APP_HTTPS_WGET_URL); - if (ret < 0) - { - return -1; - } + /* -------------------------------------- + * 2. send HTTP request (secure socket) + * -------------------------------------- + */ - /* Save to file the secure socket context needed to receive a HTTP - * response after resuming from sleep. - */ + /* HTTP requests are sent using secure socket. HTTP response will + * arrive 10 seconds later. In the meantime, Spresense sleeps and + * waits for the HTTP response, and wakes up when triggered by + * the HTTP response. + */ - ret = save_tls_contexts(&g_tls_context); - if (ret < 0) - { - return -1; - } + ret = send_https_request(&g_tls_context, APP_HTTPS_WGET_URL); + if (ret < 0) + { + return -1; + } - /* ------------------------------------------------------ - * 3. spresense cold sleep (Keep the connection to LTE) - * ------------------------------------------------------ - */ + /* Save to file the secure socket context needed to receive a HTTP + * response after resuming from sleep. + */ - /* LTE module entering hibernation mode */ + ret = save_tls_contexts(&g_tls_context); + if (ret < 0) + { + return -1; + } - printf("Entering LTE hibernation mode.\n"); + /* ------------------------------------------------------ + * 3. spresense cold sleep (Keep the connection to LTE) + * ------------------------------------------------------ + */ - ret = lte_enter_hibernation(); - if (ret < 0) - { - return -1; - } + /* LTE module entering hibernation mode */ - /* Entering cold sleep */ + printf("Entering LTE hibernation mode.\n"); - boardctl(BOARDIOC_POWEROFF, 1); + ret = lte_enter_hibernation(); + if (ret < 0) + { + return -1; } + /* Entering cold sleep */ + + boardctl(BOARDIOC_POWEROFF, 1); + return 0; } diff --git a/examples/lte_http_get/lte_http_get_main.c b/examples/lte_http_get/lte_http_get_main.c index 5386b72fa..0688ceb8c 100644 --- a/examples/lte_http_get/lte_http_get_main.c +++ b/examples/lte_http_get/lte_http_get_main.c @@ -473,7 +473,10 @@ static void app_restart_cb(uint32_t reason) { printf("Failed to recovery process :%d\n", ret); } - pthread_detach(thread_id); + else + { + pthread_detach(thread_id); + } } } diff --git a/examples/lte_lwm2m/Kconfig b/examples/lte_lwm2m/Kconfig index b422520da..292012f2e 100644 --- a/examples/lte_lwm2m/Kconfig +++ b/examples/lte_lwm2m/Kconfig @@ -26,6 +26,10 @@ config EXAMPLES_LTE_LWM2M_STACKSIZE int "lte_lwm2m stack size" default 8192 +config EXAMPLES_LTE_LWM2M_STACKSIZE_IN_USING_MBEDTLS + int "lte_lwm2m stack size in using mbedTLS" + default 11264 + config EXAMPLES_LTE_LWM2M_APN_NAME string "Access Point Name" default "" diff --git a/examples/lte_lwm2m/system_gnss.c b/examples/lte_lwm2m/system_gnss.c index 893b611b5..124dbc99d 100644 --- a/examples/lte_lwm2m/system_gnss.c +++ b/examples/lte_lwm2m/system_gnss.c @@ -197,6 +197,7 @@ static int gnss_task(int argc, char **argv) radius = sqrtf(hvar * hvar + vvar * vvar); + memset(&tm, 0, sizeof(tm)); tm.tm_sec = posdat.receiver.time.sec; tm.tm_min = posdat.receiver.time.minute; tm.tm_hour = posdat.receiver.time.hour; diff --git a/examples/multi_webcamera/README.txt b/examples/multi_webcamera/README.txt index 0a397cf5c..14de16d2e 100644 --- a/examples/multi_webcamera/README.txt +++ b/examples/multi_webcamera/README.txt @@ -31,7 +31,7 @@ examples/multi_webcamera 2. Multiple Web Camera by using original protocol. In this option, Spresense send a camera JPEG image to a client by original protocol on TCP. - In host/ directory, there is reference host programing by using Python. + In host/python directory, there is reference host programing by using Python. [How to build] @@ -144,7 +144,7 @@ examples/multi_webcamera 192.168.11.3 192.168.11.4 - On PC side, sample tool is provided in spresense/examples/multi_webcamera/host. + On PC side, sample tool is provided in spresense/examples/multi_webcamera/host/python. It is written in Python2.x with WxPython to display GUI. So you need to install smoe required pachages of python at first on you PC. Below example is in case of ubuntu 16.04. @@ -152,7 +152,7 @@ examples/multi_webcamera $ sudo apt install python-wxgtk3.0 python-wxtools After that, attach the AP network as the same as other spresense boards. - And then, execute MultiCameraFrame.py on your PC in host/ directory. + And then, execute MultiCameraFrame.py on your PC in host/python directory. $ python MultiCameraFrame.py diff --git a/examples/multi_webcamera/host/linux_video/LICENSE b/examples/multi_webcamera/host/linux_video/LICENSE new file mode 100644 index 000000000..b7eaaf4dd --- /dev/null +++ b/examples/multi_webcamera/host/linux_video/LICENSE @@ -0,0 +1,359 @@ +Valid-License-Identifier: GPL-2.0 +Valid-License-Identifier: GPL-2.0-only +Valid-License-Identifier: GPL-2.0+ +Valid-License-Identifier: GPL-2.0-or-later +SPDX-URL: https://spdx.org/licenses/GPL-2.0.html +Usage-Guide: + To use this license in source code, put one of the following SPDX + tag/value pairs into a comment according to the placement + guidelines in the licensing rules documentation. + For 'GNU General Public License (GPL) version 2 only' use: + SPDX-License-Identifier: GPL-2.0 + or + SPDX-License-Identifier: GPL-2.0-only + For 'GNU General Public License (GPL) version 2 or any later version' use: + SPDX-License-Identifier: GPL-2.0+ + or + SPDX-License-Identifier: GPL-2.0-or-later +License-Text: + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/examples/multi_webcamera/host/linux_video/README.txt b/examples/multi_webcamera/host/linux_video/README.txt new file mode 100644 index 000000000..1a649f655 --- /dev/null +++ b/examples/multi_webcamera/host/linux_video/README.txt @@ -0,0 +1,118 @@ +examples/multi_webcamera/linux_video +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + This directory contains linux driver code and user space code for + receiving jpeg camera images from spresense multiwebcam and injecting + them into linux video sub-system. + This allows the Spresense camera to be treated as a normal camera device on Linux. + + This code has been confirmed on Ubuntu 22.04 LTS running on Intel(R) Core(TM) i5-5200U CPU. + + [Overview] + + This sample works like below: + + On Spresense On Linux userspace On Linux Kernel space + +-------------+ +--------------+ +---------------+ + | multiwebcam | -- Network -> | sprcam_net | -- device file -> | spr_camera.ko | --> To Linux Video sub-system + +-------------+ +--------------+ +---------------+ + + 'sprcam_net' gets a jpeg image from 'multiwebcam' running on Spresense via TCP/IP network. + After got it, 'sprcam_net' inject the jpeg image into the linux kernel driver 'spr_camera.ko'. + 'spr_camera.ko' receives the jpeg image and inject it to linux video sub-system. + Then, the image from Spresense can be used as standard video device in linux operating system. + + [How to build] + + On Spresense side : Build multiwebcam example without an option 'CONFIG_EXAMPLES_MULTIWEBCAM_USE_HTTPMJPEG' . + + On Linux PC side: + At first, you need to prepare linux kernel driver build environment. Search web with some keyword like "linux kernel driver build environment". + From this point forward, we will assume that the Linux driver development environment has bee established. + + Build Kernel module + + Go to "driver" directory, and execute "make" command on it. + If it is successed, "spr_camera.ko" file is generated. + + Build User Space program + + Go to "userspace" directory, and execute "make" command on it. + If it is successed, "sprcam_net" file is generated. + + [How to run] + + On Spresense side: + Connect network in the same domain connected by the Linux PC. + And check IP address on the Spresense. + After that, run 'multiwebcam' sample app on the Spresense. + + On Linux PC side: + In 'driver' directory, execute "make insmod" to activate built kernel module. + Then go to 'userspace' directory, and execute "sudo ./sprcam_net ". + + Then spresense's camera jpeg image is injecting into linux video sub-system. + + Open an application with using camera, then you can see and select camera device named "sprcamera". + +===== 日本語 ===== + + このディレクトリには、SpresenseのmultiwebcamアプリからJPEG画像を受け取り、LinuxのVideoサブシステムに注入するための + Linuxドライバコードとユーザースペースで動作するアプリのコードが入っています。 + これを利用することで、SpresenseのカメラをLinux上の通常のカメラデバイスとして扱うことができます。 + + このコードはUbuntu 22.04 LTS で動作することを確認しています。 + + [概要] + + このサンプルは以下のように動作します。 + + On Spresense On Linux userspace On Linux Kernel space + +-------------+ +--------------+ +---------------+ + | multiwebcam | -- Network -> | sprcam_net | -- device file -> | spr_camera.ko | --> To Linux Video sub-system + +-------------+ +--------------+ +---------------+ + + Linux上でユーザー空間で動作する'sprcam_net'は、TCP/IPネットワークを介してSpresense上で動作する'multiwebcam'から、 + JPEG画像を取得します。取得したJPEG画像をKernel空間で動作するKernel Module(ドライバ)'spr_camera.ko'にデバイスファイルを介して送ります。 + 'spr_camera.ko'では、受け取ったJPEG画像をLinuxのVideoサブシステムに注入し、Spresenseのカメラ画像を通常のVideoデバイスとして機能させます。 + + なお、このコードは Intel(R) Core(TM) i5-5200U CPU上で動作している Ubuntu 22.04 LTS の環境で動作確認をしています。 + + [ビルド方法] + + Spresense側:multiwebcameraサンプルを、Kconfigオプション 'CONFIG_EXAMPLES_MULTIWEBCAM_USE_HTTPMJPEG' を外したものでビルドします。 + + Linux PC側: + + まずはじめに、Linux Kernelドライバのビルド環境を構築する必要があります。検索エンジンを用いて、 "linux kernel driver build environment" などと + いったキーワードで検索をして、適宜環境構築をしてください。 + 以下の説明では、ビルド環境が整っていることを前提に説明します。 + + Kernel Moduleのビルド(spr_camera.koのビルド) + + 'driver' ディレクトリに入り、"make" とコマンドを打つと、ビルドが実行され、 + 正常にビルドが完了すると、同じディレクトリに 'spr_camera.ko' というファイルが生成されます。 + + User Spaceのプログラムのビルド(sprcam_netのビルド) + + 'userspace' ディレクトリに入り、"make" とコマンドを打つと、ビルドが実行され、 + 正常にビルドが完了すると、同じディレクトリに 'sprcam_net' というファイルが生成されます。 + + [実行方法] + + Spresense側: + + まずLinux PCが接続されているネットワークドメインへSpresenseを接続します。 + (例えば、Wi-Fiの場合、PCと同じWi-Fi アクセスポイントに接続します) + その後、Spresenseの実機に振られたIPアドレスを確認し、 + 'multiwebcam' サンプルを実行します。 + + Linux PC側: + + まず、 'driver' ディレクトリにて、 "make insmod" と実行して、ビルドしたKernel ModuleをLinuxKernelに登録します。 + その後、 'userspace' ディレクトリに移り、 "sudo ./sprcam_net " と実行します。 + + これでLiinux上にSpresenseのカメラデバイスが出来、そのカメラデバイスを介してSpresenseの画像を利用することが出来ます。 + + 試しに、カメラを使うような、Linux上の通常のアプリを実行すると、カメラデバイス選択に 'sprcamera' というデバイスが見えるようになり、 + それを選択すると、Spresenseのカメラの画像をLinuxの通常のアプリで利用することが出来ます。 diff --git a/examples/multi_webcamera/host/linux_video/driver/.gitignore b/examples/multi_webcamera/host/linux_video/driver/.gitignore new file mode 100644 index 000000000..ea5342338 --- /dev/null +++ b/examples/multi_webcamera/host/linux_video/driver/.gitignore @@ -0,0 +1,13 @@ +.mod.c +.Module.symvers.cmd +.modules.order.cmd +.spr_camera.ko.cmd +.spr_camera.mod.cmd +.spr_camera.mod.o.cmd +.spr_camera.o.cmd +Module.symvers +modules.order +.ko +.mod +.mod.o +.o diff --git a/examples/multi_webcamera/host/linux_video/driver/Makefile b/examples/multi_webcamera/host/linux_video/driver/Makefile new file mode 100644 index 000000000..262cce542 --- /dev/null +++ b/examples/multi_webcamera/host/linux_video/driver/Makefile @@ -0,0 +1,15 @@ +obj-m = spr_camera.o + +all: spr_camera.ko + +spr_camera.ko: spr_camera.c spr_camera.h + make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean + +insmod: spr_camera.ko + sudo insmod spr_camera.ko + +rmmod: + sudo rmmod spr_camera diff --git a/examples/multi_webcamera/host/linux_video/driver/spr_camera.c b/examples/multi_webcamera/host/linux_video/driver/spr_camera.c new file mode 100644 index 000000000..7d6ea403f --- /dev/null +++ b/examples/multi_webcamera/host/linux_video/driver/spr_camera.c @@ -0,0 +1,915 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * spr_camera.c -- Video Capture Driver with images + * from user-space + * + * Copyright (c) 2024 + * Sony Semiconductor Solutions Corporation + */ + +/***************************************************************************** + * Include Files + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "spr_camera.h" + +// #define FAKE_CAMERA_IMAGE + +#ifdef FAKE_CAMERA_IMAGE +# include +# include + +/* pictx.h file contains jpeg image binary for testing. + * Jpeg image must be VGA size. + * These header files are generated from 'xxd -i' command. */ + +# include "test_code/include/pict1.h" +# include "test_code/include/pict2.h" +# include "test_code/include/pict3.h" +# include "test_code/include/pict4.h" +# include "test_code/include/pict5.h" +#endif /* FAKE_CAMERA_IMAGE */ + +/***************************************************************************** + * Preprocessor Definitions + *****************************************************************************/ + +#define ISNT_EQ_FIELD(fld) (fmt->fmt.pix.fld != sprcam_pix_format[0].fld) + +/***************************************************************************** + * Private Types + *****************************************************************************/ + +struct spr_camera +{ + struct v4l2_device v4dev; + struct v4l2_ctrl_handler v4hdlr; + struct video_device vdev; + struct platform_device *pdev; + struct mutex lock; + struct vb2_queue vbq; + struct list_head bufq; + u32 seqno; + struct v4l2_pix_format current_pixfmt; + struct pm_qos_request qos; + bool is_streaming; + +#ifdef FAKE_CAMERA_IMAGE + struct task_struct *dummy_thread; +#else + /* For User I/F Device file */ + + int cdev_major; + struct class *cdev_clas; + dev_t cdev_id; + bool is_cdev_opened; +#endif +}; + +struct spr_vbuf_container +{ + struct vb2_v4l2_buffer vbuf; + struct list_head queue; +}; + +/***************************************************************************** + * Private Function Prototypes + *****************************************************************************/ + +/* --------------------------------------------------------------------------*/ +/* User I/F File Operations */ + +#ifndef FAKE_CAMERA_IMAGE +static int sprcam_cdev_open(struct inode *inode, struct file *file); +static int sprcam_cdev_release(struct inode *inode, struct file *file); +static ssize_t sprcam_cdev_write(struct file *file, const char __user *buff, + size_t count, loff_t *pos); +#endif + +/* --------------------------------------------------------------------------*/ +/* vb2 callback Operations */ + +static void sprcam_vb2_queue(struct vb2_buffer *vb); +static int sprcam_vb2_prepare(struct vb2_buffer *vb); +static int sprcam_vb2_queue_setup(struct vb2_queue *vq, + unsigned int *nbufs, + unsigned int *num_planes, + unsigned int sizes[], + struct device *alloc_devs[]); +static int sprcam_vb2_start_streaming(struct vb2_queue *vq, + unsigned int count); +static void sprcam_vb2_stop_streaming(struct vb2_queue *vq); + +/* --------------------------------------------------------------------------*/ +/* Video devide File operations */ + +static int sprcam_open(struct file *filp); +static int sprcam_release(struct file *filp); + +/* --------------------------------------------------------------------------*/ +/* Video Device IO Controls */ + +static int sprcam_enum_input(struct file *filp, void *priv, + struct v4l2_input *input); +static int sprcam_g_input(struct file *filp, void *priv, unsigned int *i); +static int sprcam_s_input(struct file *filp, void *priv, unsigned int i); +static int sprcam_enum_fmt_vid_cap(struct file *filp, void *priv, + struct v4l2_fmtdesc *fmt); +static int sprcam_try_fmt_vid_cap(struct file *filp, void *priv, + struct v4l2_format *fmt); +static int sprcam_g_fmt_vid_cap(struct file *filp, void *priv, + struct v4l2_format *fmt); +static int sprcam_s_fmt_vid_cap(struct file *filp, void *priv, + struct v4l2_format *fmt); +static int sprcam_querycap(struct file *filp, void *priv, + struct v4l2_capability *cap); +static int sprcam_g_parm(struct file *filp, void *priv, + struct v4l2_streamparm *parm); +static int sprcam_s_parm(struct file *filp, void *priv, + struct v4l2_streamparm *parm); +static int sprcam_enum_framesizes(struct file *filp, void *priv, + struct v4l2_frmsizeenum *sizes); +static int sprcam_enum_frameintervals(struct file *filp, void *priv, + struct v4l2_frmivalenum *interval); + +/*----------------------------------------------------------------------------*/ +/* Platform device driver probing / removing */ + +static int sprcam_probe(struct platform_device *pdev); +static void sprcam_remove(struct platform_device *pdev); + +/***************************************************************************** + * Private Data + *****************************************************************************/ + +static struct spr_camera *g_sprcam = NULL; /* Device Driver instance */ + +static struct platform_driver sprcam_driver = +{ + .driver = + { + .name = SPRCAM_DRVNAME, + }, + .probe = sprcam_probe, + .remove_new = sprcam_remove, +}; + +static struct platform_device *my_pdev = NULL; + +/*----------------------------------------------------------------------------*/ +/* User frontend character device file operations */ + +#ifndef FAKE_CAMERA_IMAGE +static struct file_operations sprcam_cdevops = { + .owner = THIS_MODULE, + .open = sprcam_cdev_open, + .release = sprcam_cdev_release, + .write = sprcam_cdev_write, +#if 0 + .read = sprcam_cdev_read, + .unlocked_ioctl = sprcam_cdev_ioctl, +#endif +}; +#endif + +/*----------------------------------------------------------------------------*/ +/* Video Driver related structures */ + +static const struct v4l2_file_operations sprcam_vdev_fops = +{ + .owner = THIS_MODULE, + .open = sprcam_open, + .release = sprcam_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_pix_format sprcam_pix_format[] = +{ + { /* MJPEG VGA pixel format */ + .width = VGA_WIDTH, + .height = VGA_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MJPEG, + .field = V4L2_FIELD_NONE, + .bytesperline = VGA_WIDTH * 2, + .sizeimage = VGA_WIDTH * VGA_HEIGHT * 2, + .colorspace = V4L2_COLORSPACE_SRGB, + .flags = V4L2_FMT_FLAG_COMPRESSED + }, +}; +#define SPRCAM_PIXFMTNUM \ + (sizeof(sprcam_pix_format)/sizeof(sprcam_pix_format[0])) + +static const struct vb2_ops sprcam_vb2_ops = +{ + .queue_setup = sprcam_vb2_queue_setup, + .buf_queue = sprcam_vb2_queue, + .buf_prepare = sprcam_vb2_prepare, + .start_streaming = sprcam_vb2_start_streaming, + .stop_streaming = sprcam_vb2_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static const struct v4l2_ioctl_ops sprcam_ioctl_ops = +{ + .vidioc_enum_input = sprcam_enum_input, + .vidioc_g_input = sprcam_g_input, + .vidioc_s_input = sprcam_s_input, + .vidioc_enum_fmt_vid_cap = sprcam_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = sprcam_try_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = sprcam_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = sprcam_s_fmt_vid_cap, + .vidioc_querycap = sprcam_querycap, + .vidioc_g_parm = sprcam_g_parm, + .vidioc_s_parm = sprcam_s_parm, + .vidioc_enum_framesizes = sprcam_enum_framesizes, + .vidioc_enum_frameintervals = sprcam_enum_frameintervals, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static const struct video_device sprcam_video_dev = +{ + .name = SPRCAM_DRVNAME, + .minor = -1, + .fops = &sprcam_vdev_fops, + .ioctl_ops = &sprcam_ioctl_ops, + .release = video_device_release_empty, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, +}; + +#ifdef FAKE_CAMERA_IMAGE +struct dummy_data +{ + unsigned char *data; + unsigned int len; +}; + +static struct dummy_data fake_data[] = { + { pict1, pict1_len }, + { pict2, pict2_len }, + { pict3, pict3_len }, + { pict4, pict4_len }, + { pict5, pict5_len }, +}; +#endif + +/***************************************************************************** + * Private Functions + *****************************************************************************/ + +static struct spr_vbuf_container *sprcam_get_nextvbuff(struct spr_camera *sprcam) +{ + struct spr_vbuf_container *container = NULL; + + if (sprcam->is_streaming && !list_empty(&sprcam->bufq)) + { + container = list_entry(sprcam->bufq.next, + struct spr_vbuf_container, + queue); + if (container) + list_del(&container->queue); + } + + return container; +} + +#ifdef FAKE_CAMERA_IMAGE +static int sprcam_copy_vbuff(int seqno, struct spr_vbuf_container *container, + void *data, int len) +{ + void *frame_mem; + + container->vbuf.vb2_buf.timestamp = ktime_get_ns(); + container->vbuf.field = V4L2_FIELD_NONE; + container->vbuf.sequence = seqno; + + frame_mem = vb2_plane_vaddr(&container->vbuf.vb2_buf, 0); + memcpy(frame_mem, data, len); + vb2_set_plane_payload(&container->vbuf.vb2_buf, 0, len); + + vb2_buffer_done(&container->vbuf.vb2_buf, VB2_BUF_STATE_DONE); + + return 0; +} + +static int dummy_frame_event(void *arg) +{ + struct spr_camera *sprcam = (struct spr_camera *)arg; + struct spr_vbuf_container *container; + int fnum; + + while (!kthread_should_stop()) + { + msleep(33); + container = sprcam_get_nextvbuff(sprcam); + if (container) + { + fnum = sprcam->seqno % 5; + sprcam_copy_vbuff(sprcam->seqno++, container, + fake_data[fnum].data, fake_data[fnum].len); + } + } + + return 0; +} + +#else /* FAKE_CAMERA_IMAGE */ + +static int sprcam_publish_vbuf_fromuser(int seqno, + struct spr_vbuf_container *container, + const char __user *data, size_t len) +{ + void *frame_mem; + enum vb2_buffer_state state; + + container->vbuf.vb2_buf.timestamp = ktime_get_ns(); + container->vbuf.field = V4L2_FIELD_NONE; + container->vbuf.sequence = seqno; + + frame_mem = vb2_plane_vaddr(&container->vbuf.vb2_buf, 0); + if (copy_from_user(frame_mem, data, len)) + { + printk(KERN_ALERT "sprcam: Error on copy_from_user\n"); + state = VB2_BUF_STATE_ERROR; + } + else + { + vb2_set_plane_payload(&container->vbuf.vb2_buf, 0, len); + state = VB2_BUF_STATE_DONE; + } + + vb2_buffer_done(&container->vbuf.vb2_buf, state); + + return state == VB2_BUF_STATE_DONE ? 0 : -EIO; +} + +/* --------------------------------------------------------------------------*/ +/* User I/F file Operations */ + +static int sprcam_cdev_open(struct inode *inode, struct file *file) +{ + if (g_sprcam->is_cdev_opened) + { + return -EBUSY; + } + + g_sprcam->is_cdev_opened = true; + + return 0; +} + +static int sprcam_cdev_release(struct inode *inode, struct file *file) +{ + g_sprcam->is_cdev_opened = false; + return 0; +} + +static ssize_t sprcam_cdev_write(struct file *file, const char __user *buff, + size_t count, loff_t *pos) +{ + int ret = -ENODEV; + struct spr_vbuf_container *container; + + container = sprcam_get_nextvbuff(g_sprcam); + if (container) + { + ret = sprcam_publish_vbuf_fromuser(g_sprcam->seqno++, container, + buff, count); + } + + return ret; +} + +/* --------------------------------------------------------------------------*/ +/* Initialize User I/F Character Device */ + +static int sprcam_cdev_init(struct spr_camera *sprcam) +{ + printk(KERN_ALERT "sprcam: chdev init sprcam=%p\n", sprcam); + + sprcam->cdev_major = register_chrdev(0, SPRCAM_DRVNAME, &sprcam_cdevops); + if (sprcam->cdev_major < 0) + { + printk(KERN_ALERT "Registering sprcam_cdev failed with %d\n", + sprcam->cdev_major); + return sprcam->cdev_major; + } + + sprcam->cdev_id = MKDEV(sprcam->cdev_major, 0); + sprcam->cdev_clas = class_create(SPRCAM_DRVNAME); + if (sprcam->cdev_clas == NULL) + { + printk(KERN_ALERT "Cannnot create class structure\n"); + goto err_class; + } + + if (device_create(sprcam->cdev_clas, NULL, sprcam->cdev_id, sprcam, + SPRCAM_DRVNAME) == NULL) + { + printk(KERN_ALERT "Cannnot create device structure\n"); + goto err_devcreate; + } + + return 0; + +err_devcreate: + class_destroy(sprcam->cdev_clas); + +err_class: + unregister_chrdev(sprcam->cdev_major, SPRCAM_DRVNAME); + + return -ENOMEM; +} + +static void sprcam_cdev_uninit(struct spr_camera *sprcam) +{ + device_destroy(sprcam->cdev_clas, sprcam->cdev_id); + class_destroy(sprcam->cdev_clas); + unregister_chrdev(sprcam->cdev_major, SPRCAM_DRVNAME); +} +#endif /* FAKE_CAMERA_IMAGE */ + +/* --------------------------------------------------------------------------*/ +/* vb2 callback Operations */ + +static void sprcam_vb2_queue(struct vb2_buffer *vb) +{ + struct spr_camera *sprcam = vb2_get_drv_priv(vb->vb2_queue); + struct spr_vbuf_container *container = + (struct spr_vbuf_container *)to_vb2_v4l2_buffer(vb); + + list_add_tail(&container->queue, &sprcam->bufq); +} + +static int sprcam_vb2_prepare(struct vb2_buffer *vb) +{ + struct spr_camera *sprcam = vb2_get_drv_priv(vb->vb2_queue); + + if (vb2_plane_size(vb, 0) < sprcam->current_pixfmt.sizeimage) + { + printk(KERN_ALERT "Plane size too small (%lu < %u)\n", + vb2_plane_size(vb, 0), + sprcam->current_pixfmt.sizeimage); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, sprcam->current_pixfmt.sizeimage); + + return 0; +} + +static int sprcam_vb2_queue_setup(struct vb2_queue *vq, + unsigned int *nbufs, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct spr_camera *sprcam = vb2_get_drv_priv(vq); + int size = sprcam->current_pixfmt.sizeimage; + + if (*num_planes) + { + return sizes[0] < size ? -EINVAL : 0; + } + + *num_planes = 1; + sizes[0] = size; + + return 0; +} + +static int sprcam_vb2_start_streaming(struct vb2_queue *vq, + unsigned int count) +{ + struct spr_camera *sprcam = vb2_get_drv_priv(vq); + + if (sprcam->is_streaming) + { + return -EBUSY; + } + + sprcam->seqno = 0; + cpu_latency_qos_add_request(&sprcam->qos, 33 /* ms */); + +#ifdef FAKE_CAMERA_IMAGE + sprcam->dummy_thread = kthread_run(dummy_frame_event, sprcam, + "spr_cam_dummy_frameirq"); + if (IS_ERR(sprcam->dummy_thread)) + { + printk(KERN_ERR "sprcam: Failed to create kernel thread"); + cpu_latency_qos_remove_request(&sprcam->qos); + return -ENOMEM; + } +#endif /* FAKE_CAMERA_IMAGE */ + + printk(KERN_INFO "sprcam: Start streaming"); + sprcam->is_streaming = true; + + return 0; +} + +static void sprcam_vb2_stop_streaming(struct vb2_queue *vq) +{ + struct spr_camera *sprcam = vb2_get_drv_priv(vq); + struct spr_vbuf_container *container, *tmp; + + printk(KERN_INFO "sprcam: Stop streaming"); + sprcam->is_streaming = false; + +#ifdef FAKE_CAMERA_IMAGE + if (sprcam->dummy_thread) + { + kthread_stop(sprcam->dummy_thread); + sprcam->dummy_thread = NULL; + } +#endif + + cpu_latency_qos_remove_request(&sprcam->qos); + + list_for_each_entry_safe(container, tmp, &sprcam->bufq, queue) + { + list_del(&container->queue); + vb2_buffer_done(&container->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); + } +} + +/* --------------------------------------------------------------------------*/ +/* Video devide File operations */ + +static int sprcam_open(struct file *filp) +{ + int ret; + + ret = v4l2_fh_open(filp); + + return ret; +} + +static int sprcam_release(struct file *filp) +{ + _vb2_fop_release(filp, NULL); + return 0; +} + +/*----------------------------------------------------------------------------*/ +/* Video Device IO Controls */ + +static int sprcam_enum_input(struct file *filp, void *priv, + struct v4l2_input *input) +{ + if (input->index >= SPRCAM_PIXFMTNUM) + { + return -EINVAL; + } + + input->type = V4L2_INPUT_TYPE_CAMERA; + strscpy(input->name, SPRCAM_DRVNAME, sizeof(input->name)); + return 0; +} + +static int sprcam_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = SPRCAM_PIXFMTNUM - 1; + return 0; +} + +static int sprcam_s_input(struct file *filp, void *priv, unsigned int i) +{ + if (i >= SPRCAM_PIXFMTNUM) + { + return -EINVAL; + } + + return 0; +} + +static int sprcam_enum_fmt_vid_cap(struct file *filp, void *priv, + struct v4l2_fmtdesc *fmt) +{ + if (fmt->index >= SPRCAM_PIXFMTNUM) + { + return -EINVAL; + } + + fmt->pixelformat = sprcam_pix_format[fmt->index].pixelformat; + return 0; +} + +static int sprcam_try_fmt_vid_cap(struct file *filp, void *priv, + struct v4l2_format *fmt) +{ + memcpy(&fmt->fmt.pix, sprcam_pix_format, sizeof(struct v4l2_pix_format)); + return 0; +} + + +static int sprcam_g_fmt_vid_cap(struct file *filp, void *priv, + struct v4l2_format *fmt) +{ + struct spr_camera *sprcam = video_drvdata(filp); + + fmt->fmt.pix = sprcam->current_pixfmt; + return 0; +} + +static int sprcam_s_fmt_vid_cap(struct file *filp, void *priv, + struct v4l2_format *fmt) +{ + if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + { + return -ENOTSUPP; + } + + if (ISNT_EQ_FIELD(width) || ISNT_EQ_FIELD(height) || + ISNT_EQ_FIELD(pixelformat)) + { + return -ENOTSUPP; + } + + return 0; +} + +static int sprcam_querycap(struct file *filp, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, SPRCAM_DRVNAME, sizeof(cap->driver)); + strscpy(cap->card, SPRCAM_DRVNAME, sizeof(cap->card)); + strscpy(cap->bus_info, "platform:" SPRCAM_DRVNAME, sizeof(cap->bus_info)); + return 0; +} + +/* G/S_PARM */ + +static int sprcam_g_parm(struct file *filp, void *priv, + struct v4l2_streamparm *parm) +{ + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + { + return -EINVAL; + } + + parm->parm.capture.readbuffers = 2; + parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + parm->parm.capture.timeperframe.numerator = 30; + parm->parm.capture.timeperframe.denominator = 1; + + return 0; +} + +static int sprcam_s_parm(struct file *filp, void *priv, + struct v4l2_streamparm *parm) +{ + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + { + return -EINVAL; + } + + memset(&parm->parm, 0, sizeof(parm->parm)); + parm->parm.capture.readbuffers = 2; + parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + parm->parm.capture.timeperframe.numerator = 30; + parm->parm.capture.timeperframe.denominator = 1; + + return 0; +} + +static int sprcam_enum_framesizes(struct file *filp, void *priv, + struct v4l2_frmsizeenum *sizes) +{ + if (sizes->index >= SPRCAM_PIXFMTNUM) + { + return -EINVAL; + } + + if (sizes->pixel_format != sprcam_pix_format[0].pixelformat) + { + return -EINVAL; + } + + sizes->type = V4L2_FRMSIZE_TYPE_DISCRETE; + sizes->discrete.width = VGA_WIDTH; + sizes->discrete.height = VGA_HEIGHT; + + return 0; +} + +static int sprcam_enum_frameintervals(struct file *filp, void *priv, + struct v4l2_frmivalenum *interval) +{ + if (interval->index >= SPRCAM_PIXFMTNUM || + interval->pixel_format != sprcam_pix_format[0].pixelformat || + interval->width != VGA_WIDTH || interval->height != VGA_HEIGHT) + { + return -EINVAL; + } + + interval->type = V4L2_FRMIVAL_TYPE_DISCRETE; + interval->discrete.numerator = 30; + interval->discrete.denominator = 1; + return 0; +} + +/*----------------------------------------------------------------------------*/ +/* Initialize as video driver */ + +static int sprcam_videodrv_init(struct platform_device *pdev, + struct spr_camera *sprcam) +{ + int ret; + struct vb2_queue *vq; + + memcpy(&sprcam->current_pixfmt, &sprcam_pix_format[0], + sizeof(struct v4l2_pix_format)); + + sprcam->pdev = pdev; + mutex_init(&sprcam->lock); + INIT_LIST_HEAD(&sprcam->bufq); + ret = v4l2_device_register(&pdev->dev, &sprcam->v4dev); + if (ret != 0) + { + printk(KERN_ERR "sprcam: ERROR v4l2_device_register\n"); + return ret; + } + + ret = v4l2_ctrl_handler_init(&sprcam->v4hdlr, 10); + if (ret != 0) + { + printk(KERN_ERR "sprcam: ERROR v4l2_ctrl_handler_init\n"); + goto err_devreg; + } + sprcam->v4dev.ctrl_handler = &sprcam->v4hdlr; + + vq = &sprcam->vbq; + vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + vq->drv_priv = sprcam; + vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vq->buf_struct_size = sizeof(struct spr_vbuf_container); + vq->dev = sprcam->v4dev.dev; + + vq->ops = &sprcam_vb2_ops; + vq->mem_ops = &vb2_vmalloc_memops; + vq->lock = &sprcam->lock; + + ret = vb2_queue_init(vq); + if (ret != 0) + { + printk(KERN_ERR "sprcam: ERROR Video Buffer Queue Init\n"); + goto err_ctrl_handler; + } + + memcpy(&sprcam->vdev, &sprcam_video_dev, sizeof(struct video_device)); + sprcam->vdev.v4l2_dev = &sprcam->v4dev; + sprcam->vdev.lock = &sprcam->lock; + sprcam->vdev.queue = vq; + video_set_drvdata(&sprcam->vdev, sprcam); + ret = video_register_device(&sprcam->vdev, VFL_TYPE_VIDEO, -1); + if (ret != 0) + { + printk(KERN_ERR "sprcam: ERROR video_register_device\n"); + goto err_ctrl_handler; + } + + /* Initialize success */ + + return 0; + +err_ctrl_handler: + v4l2_ctrl_handler_free(&sprcam->v4hdlr); + +err_devreg: + v4l2_device_unregister(&sprcam->v4dev); + + return ret; +} + +static void sprcam_videodrv_uninit(struct spr_camera *sprcam) +{ + printk(KERN_DEBUG "sprcam: Bye Bye\n"); + video_unregister_device(&sprcam->vdev); + v4l2_ctrl_handler_free(&sprcam->v4hdlr); + v4l2_device_unregister(&sprcam->v4dev); +} + +/*----------------------------------------------------------------------------*/ +/* Platform device driver probing / removing */ + +static int sprcam_probe(struct platform_device *pdev) +{ + int ret; + + printk(KERN_DEBUG "sprcam: Proved.\n"); + + g_sprcam = kzalloc(sizeof(struct spr_camera), GFP_KERNEL); + if (g_sprcam == NULL) + { + printk(KERN_ERR "sprcam: NOMEM for spr_camera\n"); + return -ENOMEM; + } + + ret = sprcam_videodrv_init(pdev, g_sprcam); + if (ret != 0) + { + kfree(g_sprcam); + g_sprcam = NULL; + return ret; + } + +#ifndef FAKE_CAMERA_IMAGE + ret = sprcam_cdev_init(g_sprcam); + if (ret != 0) + { + sprcam_videodrv_uninit(g_sprcam); + kfree(g_sprcam); + g_sprcam = NULL; + } +#endif + + return ret; +} + +static void sprcam_remove(struct platform_device *pdev) +{ + struct spr_camera *sprcam = dev_get_drvdata(&pdev->dev); + +#ifndef FAKE_CAMERA_IMAGE + sprcam_cdev_uninit(sprcam); +#endif + sprcam_videodrv_uninit(sprcam); + + kfree(sprcam); + g_sprcam = NULL; /* Just in case */ +} + +/*----------------------------------------------------------------------------*/ +/* Initialization / Remove Functions */ + +static int __init sprcam_init(void) +{ + int ret; + my_pdev = NULL; + printk(KERN_ALERT "sprcam: Initialize: %p\n", &sprcam_driver); + ret = platform_driver_register(&sprcam_driver); + if (ret >= 0) + { + my_pdev = platform_device_register_simple(SPRCAM_DRVNAME, 0, NULL, 0); + if (!my_pdev) + { + printk(KERN_ALERT "sprcam: ERROR!!!\n"); + return -ENOMEM; + } + printk(KERN_ALERT "sprcam: dev=%p\n", my_pdev); + } + else + { + printk(KERN_ALERT "sprcam: 1:ERROR!!!\n"); + return -EIO; + } + + return 0; +} + +static void __exit sprcam_exit(void) +{ + printk(KERN_ALERT "sprcam: Exit\n"); + if (my_pdev) platform_device_unregister(my_pdev); + platform_driver_unregister(&sprcam_driver); + my_pdev = NULL; +} + +module_init(sprcam_init) +module_exit(sprcam_exit) + +MODULE_AUTHOR("Takayoshi Koizumi "); +MODULE_DESCRIPTION("Camera image injection driver for SPRESENSE"); +MODULE_LICENSE("GPL"); diff --git a/examples/multi_webcamera/host/linux_video/driver/spr_camera.h b/examples/multi_webcamera/host/linux_video/driver/spr_camera.h new file mode 100644 index 000000000..541eed080 --- /dev/null +++ b/examples/multi_webcamera/host/linux_video/driver/spr_camera.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * spr_camera.h -- Header file of video capture driver + * with images from user-space + * + * Copyright (c) 2024 + * Sony Semiconductor Solutions Corporation + */ + +#ifndef __SPR_CAMERA_H +#define __SPR_CAMERA_H + +#define SPRCAM_DRVNAME "sprcamera" + +#endif /* __SPR_CAMERA_H */ diff --git a/examples/multi_webcamera/host/linux_video/usrspace/Makefile b/examples/multi_webcamera/host/linux_video/usrspace/Makefile new file mode 100644 index 000000000..36137edcb --- /dev/null +++ b/examples/multi_webcamera/host/linux_video/usrspace/Makefile @@ -0,0 +1,11 @@ +TARGET = sprcam_net + +CSRCS = $(TARGET).c + +all: $(TARGET) + +$(TARGET): $(CSRCS) + gcc -o $(TARGET) $(CSRCS) + +clean: + rm -f sprcam_net diff --git a/examples/multi_webcamera/host/linux_video/usrspace/sprcam_net.c b/examples/multi_webcamera/host/linux_video/usrspace/sprcam_net.c new file mode 100644 index 000000000..43a29c18c --- /dev/null +++ b/examples/multi_webcamera/host/linux_video/usrspace/sprcam_net.c @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * sprcam_net.c -- JPEG Receiver and image injection to + * spr_camera driver. + * + * Copyright (c) 2024 + * Sony Semiconductor Solutions Corporation + */ + +/***************************************************************************** + * Include Files + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../driver/spr_camera.h" + +/***************************************************************************** + * Preprocessor Definitions + *****************************************************************************/ + +#define DEV_PATH "/dev/" SPRCAM_DRVNAME +#define PORT_NUM (10080) + +#define BUFF_SIZE (1024 * 1024) + +#define DEBUGGING + +/***************************************************************************** + * Private Data + *****************************************************************************/ + +static unsigned char jpgdata[BUFF_SIZE]; +static const char delim_str[4] = { 'S', 'Z', ':', ' ' }; + +/***************************************************************************** + * Private Functions + *****************************************************************************/ + +static int init_video_device(void) +{ + int fd; + + fd = open(DEV_PATH, O_RDWR); + if (fd < 0) + { + printf("Device File <%s> open error\n", DEV_PATH); + } + + return fd; +} + +static int inject_jpgdata(int fd, char *jpg, size_t len) +{ + int ret; + ret = write(fd, jpg, len); + return ret; +} + +static void finish_video_device(int fd) +{ + close(fd); +} + +static int connect_server(const char *ip) +{ + int sock; + struct sockaddr_in saddr; + + sock = socket(PF_INET, SOCK_STREAM, 0); + if (sock >= 0) + { + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = PF_INET; + saddr.sin_addr.s_addr = inet_addr(ip); + saddr.sin_port = htons(PORT_NUM); + + if (connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) != 0) + { + close(sock); + sock = -1; + } + } + + return sock; +} + +static int receive_size(int sock, char *buf, int sz) +{ + int r, ttl; + ttl = 0; + + while (ttl < sz) + { + r = recv(sock, &buf[ttl], sz - ttl, 0); + if (r < 0) + { + return -1; + } + + ttl += r; + } + + return ttl; +} + +static int is_sync_header(char *s) +{ + return s[0] == delim_str[0] && + s[1] == delim_str[1] && + s[2] == delim_str[2] && + s[3] == delim_str[3]; +} + +static int receive_jpgdata(int sock, char *buf, uint32_t len) +{ + char delim[4]; + uint32_t jpglen; + + if (receive_size(sock, delim, 4) != 4) + { + return -1; + } + + while (!is_sync_header(delim)) + { + memmove(&delim[0], &delim[1], 3); + if (receive_size(sock, &delim[3], 1) != 1) + { + return -1; + } + } + + if (receive_size(sock, (char *)&jpglen, sizeof(jpglen)) == sizeof(jpglen)) + { + if (jpglen > len) + { + printf("Receiving size is too long (%d)\n", jpglen); + return -1; + } + + if (receive_size(sock, buf, (int)jpglen) != (int)jpglen) + { + return -1; + } + } + + return (int)jpglen; +} + +#ifdef DEBUGGING +static void dump_top(unsigned char *dat, int sz) +{ + int i; + + for (i = 0; i < sz; i++) + { + printf("0x%02x", *dat++); + if (i % 16 == 15) printf("\n"); + else printf(", "); + } + + if (i % 16 != 15) printf("\n"); +} +#else +static void dump_top(unsigned char *dat, int sz) +{ +} +#endif + +/***************************************************************************** + * Public Functions + *****************************************************************************/ + +int main(int argc, char **argv) +{ + int ret; + int vdevfd; + int sockfd; + int jpglen; + + if (argc != 2) + { + printf("Usage : %s \n", argv[0]); + return -1; + } + + vdevfd = init_video_device(); + if (vdevfd < 0) + { + return -1; + } + + sockfd = connect_server(argv[1]); + if (sockfd < 0) + { + printf("Connection error : %s(%d)\n", argv[1], PORT_NUM); + finish_video_device(vdevfd); + return -1; + } + + while (1) + { + while (sockfd < 0) + { + sockfd = connect_server(argv[1]); + } + + while ((jpglen = receive_jpgdata(sockfd, jpgdata, BUFF_SIZE)) > 0) + { + dump_top(jpgdata, 16); + inject_jpgdata(vdevfd, jpgdata, jpglen); + } + + close(sockfd); + sockfd = -1; + } + + return 0; +} diff --git a/examples/multi_webcamera/host/ImgScaler.py b/examples/multi_webcamera/host/python/ImgScaler.py similarity index 100% rename from examples/multi_webcamera/host/ImgScaler.py rename to examples/multi_webcamera/host/python/ImgScaler.py diff --git a/examples/multi_webcamera/host/MultiCameraFrame.py b/examples/multi_webcamera/host/python/MultiCameraFrame.py similarity index 100% rename from examples/multi_webcamera/host/MultiCameraFrame.py rename to examples/multi_webcamera/host/python/MultiCameraFrame.py diff --git a/examples/multi_webcamera/host/NetImgReceiver.py b/examples/multi_webcamera/host/python/NetImgReceiver.py similarity index 100% rename from examples/multi_webcamera/host/NetImgReceiver.py rename to examples/multi_webcamera/host/python/NetImgReceiver.py diff --git a/examples/multi_webcamera/host/test_module/.gitignore b/examples/multi_webcamera/host/python/test_module/.gitignore similarity index 100% rename from examples/multi_webcamera/host/test_module/.gitignore rename to examples/multi_webcamera/host/python/test_module/.gitignore diff --git a/examples/multi_webcamera/host/test_module/001.jpg b/examples/multi_webcamera/host/python/test_module/001.jpg similarity index 100% rename from examples/multi_webcamera/host/test_module/001.jpg rename to examples/multi_webcamera/host/python/test_module/001.jpg diff --git a/examples/multi_webcamera/host/test_module/002.jpg b/examples/multi_webcamera/host/python/test_module/002.jpg similarity index 100% rename from examples/multi_webcamera/host/test_module/002.jpg rename to examples/multi_webcamera/host/python/test_module/002.jpg diff --git a/examples/multi_webcamera/host/test_module/003.jpg b/examples/multi_webcamera/host/python/test_module/003.jpg similarity index 100% rename from examples/multi_webcamera/host/test_module/003.jpg rename to examples/multi_webcamera/host/python/test_module/003.jpg diff --git a/examples/multi_webcamera/host/test_module/004.jpg b/examples/multi_webcamera/host/python/test_module/004.jpg similarity index 100% rename from examples/multi_webcamera/host/test_module/004.jpg rename to examples/multi_webcamera/host/python/test_module/004.jpg diff --git a/examples/multi_webcamera/host/test_module/005.jpg b/examples/multi_webcamera/host/python/test_module/005.jpg similarity index 100% rename from examples/multi_webcamera/host/test_module/005.jpg rename to examples/multi_webcamera/host/python/test_module/005.jpg diff --git a/examples/multi_webcamera/host/test_module/006.jpg b/examples/multi_webcamera/host/python/test_module/006.jpg similarity index 100% rename from examples/multi_webcamera/host/test_module/006.jpg rename to examples/multi_webcamera/host/python/test_module/006.jpg diff --git a/examples/multi_webcamera/host/test_module/007.jpg b/examples/multi_webcamera/host/python/test_module/007.jpg similarity index 100% rename from examples/multi_webcamera/host/test_module/007.jpg rename to examples/multi_webcamera/host/python/test_module/007.jpg diff --git a/examples/multi_webcamera/host/test_module/TestServer.py b/examples/multi_webcamera/host/python/test_module/TestServer.py similarity index 100% rename from examples/multi_webcamera/host/test_module/TestServer.py rename to examples/multi_webcamera/host/python/test_module/TestServer.py diff --git a/examples/multi_webcamera/host/test_module/__init__.py b/examples/multi_webcamera/host/python/test_module/__init__.py similarity index 100% rename from examples/multi_webcamera/host/test_module/__init__.py rename to examples/multi_webcamera/host/python/test_module/__init__.py diff --git a/examples/step_counter/Makefile b/examples/step_counter/Makefile index 95a611dc7..b4b2488c7 100644 --- a/examples/step_counter/Makefile +++ b/examples/step_counter/Makefile @@ -48,15 +48,8 @@ MODULE = $(CONFIG_EXAMPLES_STEP_COUNTER) MAINSRC = step_counter_main.cxx CXXSRCS = physical_sensor.cxx accel_sensor.cxx gnss_sensor.cxx -# Sensing Example paths - -SENSINGDIR = $(SDKDIR)$(DELIM)modules$(DELIM)sensing - # Sensing Example flags -CXXFLAGS += ${INCDIR_PREFIX}$(SENSINGDIR) -CXXFLAGS += ${INCDIR_PREFIX}$(SDKDIR)$(DELIM)modules$(DELIM)include - CXXFLAGS += -D_POSIX CXXFLAGS += -DUSE_MEMMGR_FENCE diff --git a/examples/uart_bridge/.gitignore b/examples/uart_bridge/.gitignore new file mode 100644 index 000000000..9c76071ab --- /dev/null +++ b/examples/uart_bridge/.gitignore @@ -0,0 +1,12 @@ +/Make.dep +/.depend +/.built +/*.asm +/*.obj +/*.rel +/*.lst +/*.sym +/*.adb +/*.lib +/*.src +/*.spk diff --git a/examples/uart_bridge/Kconfig b/examples/uart_bridge/Kconfig new file mode 100644 index 000000000..08047aa71 --- /dev/null +++ b/examples/uart_bridge/Kconfig @@ -0,0 +1,25 @@ + +config EXAMPLES_UART_BRIDGE + tristate "UART Bridge Example" + default n + ---help--- + Enable the uart_bridge app. This app is bridging data between UART0 and UART2. + +if EXAMPLES_UART_BRIDGE + +config EXAMPLES_UART_BRIDGE_PROGNAME + string "Program name" + default "uart_bridge" + ---help--- + This is the name of the program that will be use when the NSH ELF + program is installed. + +config EXAMPLES_UART_BRIDGE_PRIORITY + int "uart_bridge task priority" + default 100 + +config EXAMPLES_UART_BRIDGE_STACKSIZE + int "uart_bridge stack size" + default 2048 + +endif diff --git a/examples/uart_bridge/Make.defs b/examples/uart_bridge/Make.defs new file mode 100644 index 000000000..b37ed31f4 --- /dev/null +++ b/examples/uart_bridge/Make.defs @@ -0,0 +1,4 @@ + +ifneq ($(CONFIG_EXAMPLES_UART_BRIDGE),) +CONFIGURED_APPS += uart_bridge +endif diff --git a/examples/uart_bridge/Makefile b/examples/uart_bridge/Makefile new file mode 100644 index 000000000..8e7ff4dcf --- /dev/null +++ b/examples/uart_bridge/Makefile @@ -0,0 +1,14 @@ + +include $(APPDIR)/Make.defs +include $(SDKDIR)/Make.defs + +PROGNAME = $(CONFIG_EXAMPLES_UART_BRIDGE_PROGNAME) +PRIORITY = $(CONFIG_EXAMPLES_UART_BRIDGE_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_UART_BRIDGE_STACKSIZE) +MODULE = $(CONFIG_EXAMPLES_UART_BRIDGE) + +ASRCS = +CSRCS = +MAINSRC = uart_bridge_main.c + +include $(APPDIR)/Application.mk diff --git a/examples/uart_bridge/uart_bridge_main.c b/examples/uart_bridge/uart_bridge_main.c new file mode 100644 index 000000000..b2e6bd68b --- /dev/null +++ b/examples/uart_bridge/uart_bridge_main.c @@ -0,0 +1,125 @@ +/**************************************************************************** + * examples/uart_bridge/uart_bridge_main.c + * + * Copyright 2024 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include + +/**************************************************************************** + * Preprocessor Definitions + ****************************************************************************/ + +#define DEV_UART0 "/dev/ttyS0" +#define DEV_UART2 "/dev/ttyS2" + +#define BUFLEN (256) + +/**************************************************************************** + * Privete Data + ****************************************************************************/ + +static char buf[BUFLEN]; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + int ret; + int uart0; + int uart2; + struct pollfd pfd[2]; + + uart0 = open(DEV_UART0, O_RDWR); + uart2 = open(DEV_UART2, O_RDWR); + + if (uart0 < 0 || uart2 < 0) + { + printf("Could not open device files\n"); + close(uart0); /* Maybe opened, try close */ + close(uart2); /* Maybe opened, try close */ + return -1; + } + + fclose(stdin); + fclose(stdout); + + while (1) + { + pfd[0].fd = uart0; + pfd[0].events = POLLIN; + + pfd[1].fd = uart2; + pfd[1].events = POLLIN; + + /* Wait for receiving data from both side */ + + poll(pfd, 2, -1); + + /* Check if it receives some from uart0 */ + + if (pfd[0].revents & POLLIN) + { + ret = read(uart0, buf, BUFLEN); + write(uart2, buf, ret); + } + + /* Check if it receives some from uart2 */ + + if (pfd[1].revents & POLLIN) + { + ret = read(uart2, buf, BUFLEN); + write(uart0, buf, ret); + } + } + + /* Never reach here, but just in case */ + + close(uart0); + close(uart2); + + return 0; +} diff --git a/externals/Make.defs b/externals/Make.defs deleted file mode 100644 index d966900cd..000000000 --- a/externals/Make.defs +++ /dev/null @@ -1,83 +0,0 @@ -############################################################################ -# Common make definitions provided to all applications -# -# Copyright (C) 2011, 2014, 2016 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -# Builtin Registration - -BUILTIN_REGISTRY = $(SDKDIR)$(DELIM)system$(DELIM)builtin$(DELIM)registry - -DEPCONFIG = $(SDKDIR)$(DELIM).config - -ifeq ($(CONFIG_WINDOWS_NATIVE),y) -define REGISTER - $(Q) echo Register: $1 - $(Q) echo { "$1", $2, $3, $4 }, > "$(BUILTIN_REGISTRY)$(DELIM)$4.bdat" - $(Q) echo int $4(int argc, char *argv[]); > "$(BUILTIN_REGISTRY)$(DELIM)$4.pdat" - $(Q) touch $(BUILTIN_REGISTRY)$(DELIM).updated" -endef -else -define REGISTER - $(Q) echo "Register: $1" - $(Q) echo "{ \"$1\", $2, $3, $4 }," > "$(BUILTIN_REGISTRY)$(DELIM)$4.bdat" - $(Q) echo "int $4(int argc, char *argv[]);" > "$(BUILTIN_REGISTRY)$(DELIM)$4.pdat" - $(Q) touch "$(BUILTIN_REGISTRY)$(DELIM).updated" -endef -endif - -# Tools - -ifeq ($(CONFIG_WINDOWS_NATIVE),y) - MKKCONFIG = $(SDKDIR)\tools\mkkconfig.bat - DIRLINK = $(TOPDIR)\tools\link.bat - DIRUNLINK = $(TOPDIR)\tools\unlink.bat -else - MKKCONFIG = $(SDKDIR)/tools/mkkconfig.sh - DIRUNLINK = $(TOPDIR)/tools/unlink.sh -ifeq ($(WINTOOL),y) - DIRLINK = $(TOPDIR)/tools/copydir.sh -else - DIRLINK = $(TOPDIR)/tools/link.sh -endif -endif - -# Standard include path - -CFLAGS += ${INCDIR_PREFIX}$(SDKDIR)$(DELIM)bsp$(DELIM)include -CXXFLAGS += ${INCDIR_PREFIX}$(SDKDIR)$(DELIM)bsp$(DELIM)include -CFLAGS += ${INCDIR_PREFIX}$(SDKDIR)$(DELIM)system$(DELIM)include -CXXFLAGS += ${INCDIR_PREFIX}$(SDKDIR)$(DELIM)system$(DELIM)include - -# utility - -dequoted = $(subst ",,$1) diff --git a/externals/awsiot/awsiot.mk b/externals/awsiot/awsiot.mk deleted file mode 100644 index e774683ae..000000000 --- a/externals/awsiot/awsiot.mk +++ /dev/null @@ -1,85 +0,0 @@ -############################################################################ -# externals/awsiot/awsiot.mk -# -# Copyright 2019 Sony Corporation -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name of Sony Semiconductor Solutions Corporation nor -# the names of its contributors may be used to endorse or promote -# products derived from this software without specific prior written -# permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -AWSCOREDIR = $(EXTERNAL_DIR)$(DELIM)awsiot$(DELIM)aws-iot-device-sdk-embedded-C -AWSPLATDIR = $(AWSCOREDIR)$(DELIM)platform$(DELIM)linux - -ROOTDEPPATH += --dep-path $(AWSCOREDIR)$(DELIM)src -ROOTDEPPATH += --dep-path $(AWSCOREDIR)$(DELIM)external_libs$(DELIM)jsmn -ROOTDEPPATH += --dep-path $(AWSPLATDIR)$(DELIM)common -ROOTDEPPATH += --dep-path $(AWSPLATDIR)$(DELIM)mbedtls -ROOTDEPPATH += --dep-path $(AWSPLATDIR)$(DELIM)pthread - -VPATH += :$(AWSCOREDIR)$(DELIM)src -VPATH += :$(AWSCOREDIR)$(DELIM)external_libs$(DELIM)jsmn -VPATH += :$(AWSPLATDIR)$(DELIM)common -VPATH += :$(AWSPLATDIR)$(DELIM)mbedtls -VPATH += :$(AWSPLATDIR)$(DELIM)pthread - -ifeq ($(WINTOOL),y) -CFLAGS += -I"${shell cygpath -w $(AWSCOREDIR)$(DELIM)include}" -CFLAGS += -I"${shell cygpath -w $(AWSCOREDIR)$(DELIM)external_libs$(DELIM)jsmn}" -CFLAGS += -I"${shell cygpath -w $(AWSCOREDIR)$(DELIM)platform$(DELIM)linux$(DELIM)common}" -CFLAGS += -I"${shell cygpath -w $(AWSCOREDIR)$(DELIM)platform$(DELIM)linux$(DELIM)mbedtls}" -CFLAGS += -I"${shell cygpath -w $(AWSCOREDIR)$(DELIM)platform$(DELIM)linux$(DELIM)pthread}" -else -CFLAGS += -I$(AWSCOREDIR)$(DELIM)include -CFLAGS += -I$(AWSCOREDIR)$(DELIM)external_libs$(DELIM)jsmn -CFLAGS += -I$(AWSCOREDIR)$(DELIM)platform$(DELIM)linux$(DELIM)common -CFLAGS += -I$(AWSCOREDIR)$(DELIM)platform$(DELIM)linux$(DELIM)mbedtls -CFLAGS += -I$(AWSCOREDIR)$(DELIM)platform$(DELIM)linux$(DELIM)pthread -endif - -CSRCS += aws_iot_jobs_interface.c -CSRCS += aws_iot_jobs_json.c -CSRCS += aws_iot_jobs_topics.c -CSRCS += aws_iot_jobs_types.c -CSRCS += aws_iot_json_utils.c -CSRCS += aws_iot_mqtt_client.c -CSRCS += aws_iot_mqtt_client_common_internal.c -CSRCS += aws_iot_mqtt_client_connect.c -CSRCS += aws_iot_mqtt_client_publish.c -CSRCS += aws_iot_mqtt_client_subscribe.c -CSRCS += aws_iot_mqtt_client_unsubscribe.c -CSRCS += aws_iot_mqtt_client_yield.c -CSRCS += aws_iot_shadow_actions.c -CSRCS += aws_iot_shadow.c -CSRCS += aws_iot_shadow_json.c -CSRCS += aws_iot_shadow_records.c -CSRCS += timer.c -CSRCS += network_mbedtls_wrapper.c -CSRCS += threads_pthread_wrapper.c -CSRCS += jsmn.c - diff --git a/externals/eltres/CXM150x_SDK/CXM150x_core/CXM150x_Utility.c b/externals/eltres/CXM150x_SDK/CXM150x_core/CXM150x_Utility.c index 96f28df26..f543f1d0b 100644 --- a/externals/eltres/CXM150x_SDK/CXM150x_core/CXM150x_Utility.c +++ b/externals/eltres/CXM150x_SDK/CXM150x_core/CXM150x_Utility.c @@ -334,6 +334,7 @@ uint32_t conv_CXM150x_GNSSTime_to_string(uint8_t *p_s, uint8_t *p_date){ uint32_t val = 0; if (sscanf((char*)p_s, "%lx", &val)) { + memset(&base_time, 0, sizeof(base_time)); base_time.tm_sec = GPS_FORMAT_BASE_TIME_SEC; base_time.tm_min = GPS_FORMAT_BASE_TIME_MIN; base_time.tm_hour = GPS_FORMAT_BASE_TIME_HOUR; diff --git a/externals/micro-ecc/LibIncludes.mk b/externals/micro-ecc/LibIncludes.mk index 2821e2681..463344034 100644 --- a/externals/micro-ecc/LibIncludes.mk +++ b/externals/micro-ecc/LibIncludes.mk @@ -34,6 +34,6 @@ ############################################################################ ifeq ($(CONFIG_EXTERNALS_MICRO_ECC), y) -CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" "$(SDKDIR)/../externals/micro-ecc/micro-ecc"} -CXXFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" "$(SDKDIR)/../externals/micro-ecc/micro-ecc"} +CFLAGS += ${INCDIR_PREFIX}$(SDKDIR)/../externals/micro-ecc/micro-ecc +CXXFLAGS += ${INCDIR_PREFIX}$(SDKDIR)/../externals/micro-ecc/micro-ecc endif diff --git a/externals/micro-ecc/Makefile b/externals/micro-ecc/Makefile index bf059944a..50680d61b 100644 --- a/externals/micro-ecc/Makefile +++ b/externals/micro-ecc/Makefile @@ -40,7 +40,7 @@ BIN = libuecc$(LIBEXT) UECC = micro-ecc -CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(UECC)} +CFLAGS += ${INCDIR_PREFIX}$(UECC) CFLAGS += -D__ARM_ARCH_7M__=0 CFLAGS += -DuECC_PLATFORM=uECC_arm_thumb2 diff --git a/externals/tensorflow/Makefile b/externals/tensorflow/Makefile index 60ecf52e7..9bb9f5b22 100644 --- a/externals/tensorflow/Makefile +++ b/externals/tensorflow/Makefile @@ -50,8 +50,6 @@ CSRCS = dummy_src.c ifeq ($(CONFIG_EXTERNALS_TENSORFLOW_EXAMPLE_MICROSPEECH),y) CXXSRCS = tf_audio_provider.cxx tf_audio_util.cxx -AUDIODIR = $(SDKDIR)$(DELIM)modules$(DELIM)audio -CXXFLAGS += ${INCDIR_PREFIX}$(AUDIODIR) CXXFLAGS += -D_POSIX CXXFLAGS += -DUSE_MEMMGR_FENCE CXXFLAGS += -DATTENTION_USE_FILENAME_LINE diff --git a/firmware/spresense/version.json b/firmware/spresense/version.json index c502da6d7..934abff17 100644 --- a/firmware/spresense/version.json +++ b/firmware/spresense/version.json @@ -1,5 +1,5 @@ { "BoardName": "SPRESENSE", - "LoaderVersion": "v3.2.0", - "DownloadURL": "https://developer.sony.com/file/download/download-spresense-firmware-v3-2-0" + "LoaderVersion": "v3.3.0", + "DownloadURL": "https://developer.sony.com/file/download/download-spresense-firmware-v3-3-0" } diff --git a/install-tools.sh b/install-tools.sh index da21a96d5..82adc4f0e 100755 --- a/install-tools.sh +++ b/install-tools.sh @@ -97,10 +97,12 @@ run_progress() linux_install_tools() { - local _packages="git gperf libncurses5 libncurses5-dev flex bison genromfs pkg-config autoconf automake curl make minicom unzip" + local _packages="git gperf libncurses5 libncurses6 libncurses5-dev libncurses-dev flex bison genromfs pkg-config autoconf automake curl make minicom unzip" local _needed for p in ${_packages}; do - dpkg -s $p >/dev/null 2>&1 || _needed="${_needed} ${p}" + if LANG=C apt-cache policy $p | grep -q "Candidate:"; then + dpkg -s $p >/dev/null 2>&1 || _needed="${_needed} ${p}" + fi done if [ -n "${_needed}" ]; then diff --git a/nuttx b/nuttx index 04159c3e3..c30b37f33 160000 --- a/nuttx +++ b/nuttx @@ -1 +1 @@ -Subproject commit 04159c3e30f9d9f2d8453b55b99a544e3c0b4242 +Subproject commit c30b37f33af60e7b222848ae9d075b9c106fb71d diff --git a/sdk/.gitignore b/sdk/.gitignore index 73f92e094..3845c69b9 100644 --- a/sdk/.gitignore +++ b/sdk/.gitignore @@ -27,10 +27,11 @@ Make.dep /.project /.settings /pcode -/tags +tags /*.log .*.tmp .context /Kconfig +/workerspks .built sdk-export.tar.gz diff --git a/sdk/apps b/sdk/apps index 1394db37d..9ceda85ee 160000 --- a/sdk/apps +++ b/sdk/apps @@ -1 +1 @@ -Subproject commit 1394db37df059b375169fc409affb8f67b214d23 +Subproject commit 9ceda85ee10845fe82faa377bafc1df2d514454f diff --git a/sdk/configs/examples/audiolite_fft/README.txt b/sdk/configs/examples/audiolite_fft/README.txt new file mode 100644 index 000000000..368e55789 --- /dev/null +++ b/sdk/configs/examples/audiolite_fft/README.txt @@ -0,0 +1,6 @@ +This configuration contains required options to use audiolite_fft example. +This example has a tutrial document to make the same user app as this example +by a user. Please look at examples/audiolite_fft/README.md. + +[Source path] +examples/audiolite_fft diff --git a/sdk/configs/examples/audiolite_fft/defconfig b/sdk/configs/examples/audiolite_fft/defconfig new file mode 100644 index 000000000..e545b38d0 --- /dev/null +++ b/sdk/configs/examples/audiolite_fft/defconfig @@ -0,0 +1,19 @@ +-MMCSD=y +-MMCSD_SDIO=y +-SCHED_LPWORK=y ++ASMP=y ++ASMP_WORKER_CMSIS=y ++ASMP_WORKER_FMSYNTH=y ++ASMP_WORKER_LIBC=y ++AUDIO=y ++AUDIO_CXD56=y ++AUDIO_FORMAT_MP3=n ++AUDIO_FORMAT_PCM=n ++AUDIO_LITE=y ++CXD56_SDCARD_AUTOMOUNT=y ++CXD56_SDIO=y ++DRIVERS_AUDIO=y ++EXAMPLES_AUDIOLITE_FFT=y ++EXTERNALS_CMSIS=y ++EXTERNALS_MOSSFW=y ++FS_AUTOMOUNTER=y diff --git a/sdk/configs/examples/audiolite_mp3player_build_elf/README.txt b/sdk/configs/examples/audiolite_mp3player_build_elf/README.txt new file mode 100644 index 000000000..bd5830666 --- /dev/null +++ b/sdk/configs/examples/audiolite_mp3player_build_elf/README.txt @@ -0,0 +1,6 @@ +This configuration contains required options to use audiolite_mp3player example. +And contains required options to build mp3dec worker as ELF file. + +[Source path] +examples/audiolite_mp3player +sdk/modules/audiolite/worker/mp3dec diff --git a/sdk/configs/examples/audiolite_mp3player_build_elf/defconfig b/sdk/configs/examples/audiolite_mp3player_build_elf/defconfig new file mode 100644 index 000000000..70f42891a --- /dev/null +++ b/sdk/configs/examples/audiolite_mp3player_build_elf/defconfig @@ -0,0 +1,19 @@ +-MMCSD=y +-MMCSD_SDIO=y +-SCHED_LPWORK=y ++ASMP=y ++ASMP_WORKER_LIBC=y ++ASMP_WORKER_CMSIS=y ++AUDIO=y ++AUDIO_CXD56=y ++AUDIO_FORMAT_MP3=n ++AUDIO_FORMAT_PCM=n ++AUDIO_LITE=y ++AUDIO_LITE_MP3DEC_SUBCORE_ELF=y ++CXD56_SDCARD_AUTOMOUNT=y ++CXD56_SDIO=y ++DRIVERS_AUDIO=y ++EXAMPLES_AUDIOLITE_MP3PLAYER=y ++EXTERNALS_CMSIS=y ++EXTERNALS_MOSSFW=y ++FS_AUTOMOUNTER=y diff --git a/sdk/configs/examples/audiolite_mp3player_build_spk/README.txt b/sdk/configs/examples/audiolite_mp3player_build_spk/README.txt new file mode 100644 index 000000000..257fab2fa --- /dev/null +++ b/sdk/configs/examples/audiolite_mp3player_build_spk/README.txt @@ -0,0 +1,6 @@ +This configuration contains required options to use audiolite_mp3player example. +And contains required options to build mp3dec worker as spk file. + +[Source path] +examples/audiolite_mp3player +sdk/modules/audiolite/worker/mp3dec diff --git a/sdk/configs/examples/audiolite_mp3player_build_spk/defconfig b/sdk/configs/examples/audiolite_mp3player_build_spk/defconfig new file mode 100644 index 000000000..80d7b4d29 --- /dev/null +++ b/sdk/configs/examples/audiolite_mp3player_build_spk/defconfig @@ -0,0 +1,19 @@ +-MMCSD=y +-MMCSD_SDIO=y +-SCHED_LPWORK=y ++ASMP=y ++ASMP_WORKER_LIBC=y ++ASMP_WORKER_CMSIS=y ++AUDIO=y ++AUDIO_CXD56=y ++AUDIO_FORMAT_MP3=n ++AUDIO_FORMAT_PCM=n ++AUDIO_LITE=y ++AUDIO_LITE_MP3DEC_SUBCORE_SPK_BUILD=y ++CXD56_SDCARD_AUTOMOUNT=y ++CXD56_SDIO=y ++DRIVERS_AUDIO=y ++EXAMPLES_AUDIOLITE_MP3PLAYER=y ++EXTERNALS_CMSIS=y ++EXTERNALS_MOSSFW=y ++FS_AUTOMOUNTER=y diff --git a/sdk/configs/examples/ble_mouse_central/README.txt b/sdk/configs/examples/ble_mouse_central/README.txt new file mode 100644 index 000000000..ea652b691 --- /dev/null +++ b/sdk/configs/examples/ble_mouse_central/README.txt @@ -0,0 +1,5 @@ +This configuration contains required options to use BLE central example +application that connects with BLE HID mouse device. + +[Source path] +examples/ble_mouse_central diff --git a/sdk/configs/examples/ble_mouse_central/defconfig b/sdk/configs/examples/ble_mouse_central/defconfig new file mode 100644 index 000000000..fcfdda024 --- /dev/null +++ b/sdk/configs/examples/ble_mouse_central/defconfig @@ -0,0 +1,5 @@ ++BLUETOOTH=y ++BLUETOOTH_NRF52=y ++EXAMPLES_BLE_MOUSE_CENTRAL=y ++EXTERNALS_MICRO_ECC=y ++EXTERNALS_NRF52=y diff --git a/sdk/configs/examples/ble_toio_central/README.txt b/sdk/configs/examples/ble_toio_central/README.txt new file mode 100644 index 000000000..b74a621a9 --- /dev/null +++ b/sdk/configs/examples/ble_toio_central/README.txt @@ -0,0 +1,5 @@ +This configuration contains required options to use BLE central example +application that connects with toio device. + +[Source path] +examples/ble_toio_central diff --git a/sdk/configs/examples/ble_toio_central/defconfig b/sdk/configs/examples/ble_toio_central/defconfig new file mode 100644 index 000000000..1bea11871 --- /dev/null +++ b/sdk/configs/examples/ble_toio_central/defconfig @@ -0,0 +1,5 @@ ++BLUETOOTH=y ++BLUETOOTH_NRF52=y ++EXAMPLES_BLE_TOIO_CENTRAL=y ++EXTERNALS_MICRO_ECC=y ++EXTERNALS_NRF52=y diff --git a/sdk/configs/examples/fmsynth/defconfig b/sdk/configs/examples/fmsynth/defconfig index f092ae660..a123b5023 100644 --- a/sdk/configs/examples/fmsynth/defconfig +++ b/sdk/configs/examples/fmsynth/defconfig @@ -3,7 +3,6 @@ +AUDIOUTILS_MMLPARSER_LIB=y +AUDIOUTILS_NXAUDIO_LIB=y +AUDIO_CXD56=y -+AUDIO_CXD56_SRC=y +AUDIO_FORMAT_MP3=n +AUDIO_FORMAT_PCM=n +DRIVERS_AUDIO=y diff --git a/sdk/configs/examples/nrc7292_fwupdate/README.txt b/sdk/configs/examples/nrc7292_fwupdate/README.txt new file mode 100644 index 000000000..0fff30858 --- /dev/null +++ b/sdk/configs/examples/nrc7292_fwupdate/README.txt @@ -0,0 +1,4 @@ +This configuration contains required options to use nrc7292 fwupdate example. + +[Source path] +sdk/apps/examples/nrc7292_fwupdate diff --git a/sdk/configs/examples/nrc7292_fwupdate/defconfig b/sdk/configs/examples/nrc7292_fwupdate/defconfig new file mode 100644 index 000000000..8906509be --- /dev/null +++ b/sdk/configs/examples/nrc7292_fwupdate/defconfig @@ -0,0 +1,17 @@ +-LIBC_IPv4_ADDRCONV=y +-NET_IPv4=n +-NET_USRSOCK_TCP=y +-PIPES=y +-SPI=y ++CXD56_NRC_HALOW=y ++DRIVERS_WIRELESS=y ++EXAMPLES_NRC7292_FWUPDATE=y ++NETDEV_WIRELESS_IOCTL=y ++NETUTILS_PING=y ++NET_ARP=n ++NET_ICMP_NO_STACK=y ++WIRELESS_NRC7292=y ++WIRELESS_WAPI=y ++WIRELESS_WAPI_CMDTOOL=y ++WIRELESS_WAPI_USOCKDTERM_CMDTOOL=y ++WL_NRC7292=y diff --git a/sdk/configs/examples/uart_bridge/README.txt b/sdk/configs/examples/uart_bridge/README.txt new file mode 100644 index 000000000..d73839cfd --- /dev/null +++ b/sdk/configs/examples/uart_bridge/README.txt @@ -0,0 +1,4 @@ +This configuration contains required options to use uart_bridge example. + +[Source path] +examples/uart_bridge diff --git a/sdk/configs/examples/uart_bridge/defconfig b/sdk/configs/examples/uart_bridge/defconfig new file mode 100644 index 000000000..6af02f74c --- /dev/null +++ b/sdk/configs/examples/uart_bridge/defconfig @@ -0,0 +1 @@ ++EXAMPLES_UART_BRIDGE=y diff --git a/sdk/configs/feature/audiolite/defconfig b/sdk/configs/feature/audiolite/defconfig index 731c69a8f..7379795e1 100644 --- a/sdk/configs/feature/audiolite/defconfig +++ b/sdk/configs/feature/audiolite/defconfig @@ -2,6 +2,9 @@ -MMCSD_SDIO=y -SCHED_LPWORK=y +ASMP=y ++ASMP_WORKER_CMSIS=y ++ASMP_WORKER_FMSYNTH=y ++ASMP_WORKER_LIBC=y +AUDIO=y +AUDIO_CXD56=y +AUDIO_FORMAT_MP3=n @@ -10,5 +13,6 @@ +CXD56_SDCARD_AUTOMOUNT=y +CXD56_SDIO=y +DRIVERS_AUDIO=y ++EXTERNALS_CMSIS=y +EXTERNALS_MOSSFW=y +FS_AUTOMOUNTER=y diff --git a/sdk/configs/feature/wifi_halow/README.txt b/sdk/configs/feature/wifi_halow/README.txt new file mode 100644 index 000000000..5db7a4398 --- /dev/null +++ b/sdk/configs/feature/wifi_halow/README.txt @@ -0,0 +1 @@ +This configuration contains required options to use Wi-Fi Halow feature with NRC7292 add-on board. diff --git a/sdk/configs/feature/wifi_halow/defconfig b/sdk/configs/feature/wifi_halow/defconfig new file mode 100644 index 000000000..92548e4f0 --- /dev/null +++ b/sdk/configs/feature/wifi_halow/defconfig @@ -0,0 +1,19 @@ +-LIBC_IPv4_ADDRCONV=y +-NET_IPv4=n ++NET_SOCKOPTS=y +-NET_USRSOCK_TCP=y +-PIPES=y +-SPI=y ++CXD56_NRC_HALOW=y ++DRIVERS_WIRELESS=y ++NETDEV_WIRELESS_IOCTL=y ++NETDEV_IOCTL=y ++NETUTILS_PING=y ++NET_ARP=n ++NET_ICMP_NO_STACK=y ++WIRELESS_WAPI=y ++WL_NRC7292=y ++WIRELESS_NRC7292=y ++WIRELESS_WAPI_CMDTOOL=y ++WIRELESS_WAPI_USOCKDTERM_CMDTOOL=y + diff --git a/sdk/modules/asmp/Kconfig b/sdk/modules/asmp/Kconfig index a28e6efcd..62c761431 100644 --- a/sdk/modules/asmp/Kconfig +++ b/sdk/modules/asmp/Kconfig @@ -25,12 +25,29 @@ config ASMP_SMALL_BLOCK Use small block size (64 KiB) to memory management. This option is for improve memory usage, but it tends to fragmentation. +menu "ASMP Worker libraries" + config ASMP_WORKER_LIBC bool "Support some libc functions in worker" default n ---help--- Support some libraries such as ctype, string, queue, fixedmath and etc. in worker. +config ASMP_WORKER_CMSIS + bool "Support ARM CMSIS math library in worker" + default n + ---help--- + Support ARM CMSIS math library in worker. For enabling this, you must set + CONFIG_EXTERNALS_CMSIS to build the library itself. + +config ASMP_WORKER_FMSYNTH + bool "Support fmsynth library in worker" + default n + ---help--- + Support fmsynth library. The code is in sdk/apps/audioutils/fmsynth + +endmenu + config ASMP_DEBUG_FEATURE bool "ASMP Framework debug feature" diff --git a/sdk/modules/asmp/worker/Makefile b/sdk/modules/asmp/worker/Makefile index 3a99c6f7f..7e3f14480 100644 --- a/sdk/modules/asmp/worker/Makefile +++ b/sdk/modules/asmp/worker/Makefile @@ -36,17 +36,19 @@ include $(APPDIR)/Make.defs -include $(SDKDIR)/Make.defs -include worker_libc.mk +include mkfiles/libc.mk +include mkfiles/fmsynth.mk +include mkfiles/cmsis.mk -VPATH = arch $(LIBC_TGTPATH) +VPATH = arch $(EXT_VPATH) SUBDIRS = -DEPPATH = --dep-path arch --dep-path . $(LIBC_DEPPATH) +DEPPATH = --dep-path arch --dep-path . $(EXT_DEPPATH) ASRCS = exception.S -CSRCS = common.c mpmq.c mpmutex.c mpshm.c -CSRCS += cpufifo.c cpuid.c doirq.c startup.c sysctl.c clock.c timer.c -CSRCS += $(LIBC_CSRCS) +CSRCS = common.c mpmq.c mpmutex.c mpshm.c printf.c +CSRCS += cpufifo.c cpuid.c doirq.c startup.c sysctl.c clock.c timer.c lowputc.c delay.c +CSRCS += $(EXT_CSRCS) AOBJS = $(ASRCS:.S=$(OBJEXT)) COBJS = $(CSRCS:.c=$(OBJEXT)) @@ -60,18 +62,18 @@ BIN = libasmpw$(LIBEXT) ARCHSRCDIR = $(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src -CFLAGS := $(LIBC_INCPATH) $(CFLAGS) +CFLAGS := $(EXT_INCPATH) $(CFLAGS) CFLAGS += ${INCDIR_PREFIX}$(ARCHSRCDIR)$(DELIM)chip CFLAGS += ${INCDIR_PREFIX}$(ARCHSRCDIR)$(DELIM)common ifneq ($(CONFIG_ARCH_FAMILY),) CFLAGS += ${INCDIR_PREFIX}$(ARCHSRCDIR)$(DELIM)$(CONFIG_ARCH_FAMILY) endif -CFLAGS += -fno-tree-loop-distribute-patterns +CFLAGS += -fno-tree-loop-distribute-patterns -DCXD5602_WORKER AFLAGS += -isystem $(SDKDIR)/modules/include -all: $(BIN) +all: $(BIN) | $(EXT_LIBS) .PHONY: context depend clean distclean $(AOBJS): %$(OBJEXT): %.S diff --git a/sdk/modules/asmp/worker/arch/delay.c b/sdk/modules/asmp/worker/arch/delay.c new file mode 100644 index 000000000..2337a84b0 --- /dev/null +++ b/sdk/modules/asmp/worker/arch/delay.c @@ -0,0 +1,114 @@ +/**************************************************************************** + * asmp/worker/arch/delay.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * 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. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include + +#include "clock.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_CXD56_USE_SYSBUS +# define CXD56XX_LOOPSPERMSEC_156MHZ 15533ull +#else +# define CXD56XX_LOOPSPERMSEC_156MHZ 7428ull +#endif + +#define CXD56XX_LOOPSPERMSEC_BY_CLOCK(clock) \ + (uint32_t)(CXD56XX_LOOPSPERMSEC_156MHZ * (clock) / 156000000ull) + +/* Adjust manually to be up_udelay(1000) is neary equal with up_udelay(999) */ + +#ifdef CONFIG_CXD56_USE_SYSBUS +# define CXD56XX_LOOPSPERUSEC_ADJUST 1010ul; +#else +# define CXD56XX_LOOPSPERUSEC_ADJUST 810ul; +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_mdelay + * + * Description: + * Delay inline for the requested number of milliseconds. + * *** NOT multi-tasking friendly *** + * + ****************************************************************************/ + +void up_mdelay(unsigned int milliseconds) +{ + volatile unsigned int i; + volatile unsigned int j; + uint32_t clock = clock_getcpubaseclock(); + uint32_t loops = CXD56XX_LOOPSPERMSEC_BY_CLOCK(clock); + + for (i = 0; i < milliseconds; i++) + { + for (j = 0; j < loops; j++) + { + } + } +} + +/**************************************************************************** + * Name: up_udelay + * + * Description: + * Delay inline for the requested number of microseconds. NOTE: Because + * of all of the setup, several microseconds will be lost before the actual + * timing loop begins. Thus, the delay will always be a few microseconds + * longer than requested. + * + * *** NOT multi-tasking friendly *** + * + ****************************************************************************/ + +void up_udelay(useconds_t microseconds) +{ + volatile unsigned int i; + volatile unsigned int j; + uint32_t clock = clock_getcpubaseclock(); + uint32_t loops = CXD56XX_LOOPSPERMSEC_BY_CLOCK(clock); + uint32_t milliseconds = microseconds / 1000; + + for (i = 0; i < milliseconds; i++) + { + for (j = 0; j < loops; j++) + { + } + } + + loops = loops * (microseconds % 1000) / CXD56XX_LOOPSPERUSEC_ADJUST; + for (i = 0; i < loops; i++) + { + } +} diff --git a/sdk/modules/asmp/worker/arch/lowputc.c b/sdk/modules/asmp/worker/arch/lowputc.c new file mode 100644 index 000000000..052e541f2 --- /dev/null +++ b/sdk/modules/asmp/worker/arch/lowputc.c @@ -0,0 +1,59 @@ +/**************************************************************************** + * modules/asmp/worker/arch/lowputc.c + * + * Copyright 2024 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "hardware/cxd56_uart.h" +#include "hardware/cxd5602_memorymap.h" +#include "arm_internal.h" + +#include "arch/lowputc.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void lowputc(const char ch) +{ + /* Wait for the transmitter to be available */ + + while ((getreg32(CXD56_UART1_BASE + CXD56_UART_FR) & UART_FLAG_TXFF)); + + /* Send the character */ + + putreg32((uint32_t)ch, CXD56_UART1_BASE + CXD56_UART_DR); +} diff --git a/sdk/modules/asmp/worker/arch/lowputc.h b/sdk/modules/asmp/worker/arch/lowputc.h new file mode 100644 index 000000000..65e627860 --- /dev/null +++ b/sdk/modules/asmp/worker/arch/lowputc.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * modules/asmp/worker/arch/lowputc.h + * + * Copyright 2024 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef _ASMP_WORKER_ARCH_LOWPUTC_H_ +#define _ASMP_WORKER_ARCH_LOWPUTC_H_ + +void lowputc(const char ch); + +#endif + diff --git a/sdk/modules/asmp/worker/mkfiles/cmsis.mk b/sdk/modules/asmp/worker/mkfiles/cmsis.mk new file mode 100644 index 000000000..d06ea468f --- /dev/null +++ b/sdk/modules/asmp/worker/mkfiles/cmsis.mk @@ -0,0 +1,25 @@ +ifneq ($(CONFIG_ASMP_WORKER_CMSIS),) + +ifneq ($(CONFIG_EXTERNALS_CMSIS),y) +$(error You must set CONFIG_EXTERNALS_CMSIS to use it in worker) +endif + +EXT_LIBS ?= + +CMSISDIR = $(SDKDIR)$(DELIM)..$(DELIM)externals$(DELIM)cmsis +CMSIS_DSP_DIR = $(CMSISDIR)$(DELIM)dsp + +# Setup to build and linking CMSIS DSP library + +include $(CMSISDIR)/LibIncludes.mk + +CMSIS_DSP_LIB = $(CMSIS_DSP_DIR)$(DELIM)libarm_cortexM4lf_math$(LIBEXT) +LDLIBPATH += -L $(CMSIS_DSP_DIR) +LDLIBS += -larm_cortexM4lf_math + +$(CMSIS_DSP_LIB): + $(Q) $(MAKE) -C $(CMSIS_DSP_DIR) TOPDIR="$(TOPDIR)" SDKDIR="$(SDKDIR)" APPDIR="$(APPDIR)" + +EXT_LIBS += $(CMSIS_DSP_LIB) + +endif diff --git a/sdk/modules/asmp/worker/mkfiles/fmsynth.mk b/sdk/modules/asmp/worker/mkfiles/fmsynth.mk new file mode 100644 index 000000000..2dbab51d4 --- /dev/null +++ b/sdk/modules/asmp/worker/mkfiles/fmsynth.mk @@ -0,0 +1,51 @@ +############################################################################ +# modules/asmp/worker/bin/fmsynth.mk +# +# Copyright 2024 Sony Semiconductor Solutions Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name of Sony Semiconductor Solutions Corporation nor +# the names of its contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +ifneq ($(CONFIG_ASMP_WORKER_FMSYNTH),) + +EXT_VPATH ?= +EXT_DEPPATH ?= +EXT_CSRCS ?= +EXT_INCPATH ?= + +NXAPPS_INCPATH = $(SDKDIR)/apps/include +FMSYNTH_PATH = $(SDKDIR)/apps/audioutils/fmsynth + +EXT_VPATH += $(FMSYNTH_PATH) +EXT_DEPPATH += --dep-path $(FMSYNTH_PATH) +EXT_CSRCS += $(notdir $(wildcard $(FMSYNTH_PATH)/*.c)) +EXT_INCPATH += -I $(NXAPPS_INCPATH) + +endif diff --git a/sdk/modules/asmp/worker/worker_libc.mk b/sdk/modules/asmp/worker/mkfiles/libc.mk similarity index 80% rename from sdk/modules/asmp/worker/worker_libc.mk rename to sdk/modules/asmp/worker/mkfiles/libc.mk index 4b0004505..2f01060fd 100644 --- a/sdk/modules/asmp/worker/worker_libc.mk +++ b/sdk/modules/asmp/worker/mkfiles/libc.mk @@ -1,5 +1,5 @@ ############################################################################ -# modules/asmp/worker/worker_libc.mk +# modules/asmp/worker/mkfiles/libc.mk # # Copyright 2023 Sony Semiconductor Solutions Corporation # @@ -35,6 +35,11 @@ ifneq ($(CONFIG_ASMP_WORKER_LIBC),) +EXT_VPATH ?= +EXT_DEPPATH ?= +EXT_CSRCS ?= +EXT_INCPATH ?= + NXINC_PATH = $(SDKDIR)/../nuttx/include LIBC_PATH = $(SDKDIR)/../nuttx/libs/libc LIBM_PATH = $(SDKDIR)/../nuttx/libs/libm @@ -44,12 +49,18 @@ LIBC_LIBS += fixedmath LIBC_LIBS += string LIBC_LIBS += queue -LIBC_EXTRA_SRC = lib_modff.c lib_floorf.c lib_fabsf.c +LIBC_EXTRA_SRC = lib_modff.c lib_floorf.c lib_fabsf.c lib_libexpif.c lib_expf.c lib_logf.c -LIBC_LIBSPATH = $(patsubst %,$(LIBC_PATH)/%,$(LIBC_LIBS)) +LIBC_LIBSPATH = $(patsubst %,$(LIBC_PATH)/%,$(LIBC_LIBS)) $(LIBM_PATH)/libm LIBC_TGTPATH = $(LIBC_LIBSPATH) $(LIBM_PATH)/libm -LIBC_CSRCS = $(notdir $(foreach p,$(LIBC_LIBSPATH),$(wildcard $(p)/*.c))) $(LIBC_EXTRA_SRC) +# LIBC_CSRCS = $(notdir $(foreach p,$(LIBC_LIBSPATH),$(wildcard $(p)/*.c))) $(LIBC_EXTRA_SRC) +LIBC_CSRCS = $(notdir $(foreach p,$(LIBC_LIBSPATH),$(wildcard $(p)/*.c))) LIBC_DEPPATH = --dep-path $(NXINC_PATH) --dep-path $(NXINC_PATH)/nuttx/lib $(patsubst %,--dep-path %,$(LIBC_TGTPATH)) -LIBC_INCPATH = -I$(NXINC_PATH) -I$(NXINC_PATH)/nuttx/lib -I$(LIBC_PATH) -DCONFIG_ARCH_STDARG_H +LIBC_INCPATH = -I$(NXINC_PATH) -I$(NXINC_PATH)/nuttx/lib -I$(LIBC_PATH) -DCONFIG_ARCH_STDARG_H -DCONFIG_LIBM + +EXT_VPATH += $(LIBC_TGTPATH) +EXT_DEPPATH += $(LIBC_DEPPATH) +EXT_CSRCS += $(LIBC_CSRCS) +EXT_INCPATH += $(LIBC_INCPATH) endif diff --git a/sdk/modules/asmp/worker/printf.c b/sdk/modules/asmp/worker/printf.c new file mode 100644 index 000000000..8fcaf7022 --- /dev/null +++ b/sdk/modules/asmp/worker/printf.c @@ -0,0 +1,542 @@ +/**************************************************************************** + * modules/asmp/worker/printf.c + * + * Copyright 2024 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include "arch/lowputc.h" + +/**************************************************************************** + * Pri-processor Definitions + ****************************************************************************/ + +#ifndef NULL +# define NULL ((void *)0) +#endif + +#define INT_DIGITTOP (1000000000) + +#define ARGPARSE_FLAG_ZFILL (1<<0) +#define ARGPARSE_FLAG_MINUS (1<<1) +#define ARGPARSE_FLAG_PLUS (1<<2) +#define ARGPARSE_FLAG_LEFT (1<<3) +#define ARGPARSE_FLAG_NEGVAL (1<<4) + +#define VALPARSE_TYPE_CHAR 1 +#define VALPARSE_TYPE_SINT 2 +#define VALPARSE_TYPE_UINT 3 +#define VALPARSE_TYPE_HEXL 4 +#define VALPARSE_TYPE_HEXH 5 +#define VALPARSE_TYPE_PTR 6 +#define VALPARSE_TYPE_STR 7 + +#define PARSE_PHASE_INITIAL 0 +#define PARSE_PHASE_PLSMIN 1 +#define PARSE_PHASE_ZFILL 2 +#define PARSE_PHASE_DIGIT 3 +#define PARSE_PHASE_DONE 4 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct arg_parse_s +{ + unsigned int flag; /* bit map of ARGPARSE_FLAG_XXXX */ + int digit_specify; /* Store digit value. e.x. %8x -> 8 */ + int type; /* Parsed type as VALPARSE_TYPE_XXXX */ + union + { + unsigned char c; /* for %c */ + unsigned int u; /* for %p, %d, %u, %x, %X */ + char *cp; /* for %s */ + } value; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int lowputs(const char *str) +{ + int ret = 0; + while (*str) + { + lowputc(*str++); + ret++; + } + + return ret; +} + +/* print_hex(): print hexiagonal value */ + +static int print_hex(struct arg_parse_s *arg, char h) +{ + int tmp; + int val; + int pos = 0; + unsigned int mask = 0xf0000000; + unsigned int shift = 28; + char value_buf[12]; + int pad_len; + char pad_char; + + tmp = 0; + for (mask = 0xf0000000, shift = 28; mask; mask >>= 4, shift -= 4) + { + val = (arg->value.u & mask) >> shift; + if (tmp || val != 0) + { + value_buf[pos++] = val >= 10 ? val + h - 10 : val + '0'; + tmp = 1; + } + } + + if (pos == 0) + { + value_buf[pos++] = '0'; + } + + if (arg->digit_specify) + { + arg->digit_specify = arg->digit_specify > 10 ? 10 : arg->digit_specify; + pad_char = arg->flag & ARGPARSE_FLAG_ZFILL ? '0' : ' '; + if (arg->digit_specify > pos) + { + pad_len = arg->digit_specify - pos; + for (tmp = pos - 1; tmp >= 0; tmp--) + { + value_buf[tmp + pad_len] = value_buf[tmp]; + } + + for (tmp = 0; tmp < pad_len; tmp++) + { + value_buf[tmp] = pad_char; + } + + pos += pad_len; + } + } + + value_buf[pos] = '\0'; + lowputs(value_buf); + + return pos; +} + +/* print_int(): print integer value */ + +static int print_int(struct arg_parse_s *arg) +{ + int val; + int tmp = 0; + int pos = 0; + unsigned int digit = INT_DIGITTOP; + char value_buf[12]; + int pad_len; + char pad_char; + + if (arg->flag & ARGPARSE_FLAG_PLUS || arg->flag & ARGPARSE_FLAG_NEGVAL) + { + value_buf[pos++] = arg->flag & ARGPARSE_FLAG_NEGVAL ? '-' : '+'; + } + + while (digit) + { + val = arg->value.u / digit; + if (tmp || val != 0) /* tmp indicates print is started or not. */ + { + val = (val >= 10) ? 9 : val; + value_buf[pos++] = val + '0'; + tmp = 1; + } + + arg->value.u = arg->value.u - (val * digit); + digit = digit / 10; + } + + if (pos == 0) + { + value_buf[pos++] = '0'; + } + + if (arg->digit_specify) + { + arg->digit_specify = arg->digit_specify > 10 ? 10 : arg->digit_specify; + pad_char = arg->flag & ARGPARSE_FLAG_ZFILL ? '0' : ' '; + if (arg->digit_specify > pos) + { + pad_len = arg->digit_specify - pos; + if (arg->flag & ARGPARSE_FLAG_MINUS) + { + for (; pad_len; pad_len--) + { + value_buf[pos++] = pad_char; + } + } + else + { + for (tmp = pos - 1; tmp >= 0; tmp--) + { + value_buf[tmp + pad_len] = value_buf[tmp]; + } + + for (tmp = 0; tmp < pad_len; tmp++) + { + value_buf[tmp] = pad_char; + } + } + + pos += pad_len; + } + } + + value_buf[pos] = '\0'; + lowputs(value_buf); + + return pos; +} + +/* type_specify(): parse type in string */ + +static int type_specify(const char c) +{ + switch (c) + { + case 'c': return VALPARSE_TYPE_CHAR; + case 'd': return VALPARSE_TYPE_SINT; + case 'u': return VALPARSE_TYPE_UINT; + case 'x': return VALPARSE_TYPE_HEXL; + case 'X': return VALPARSE_TYPE_HEXH; + case 'p': return VALPARSE_TYPE_PTR; + case 's': return VALPARSE_TYPE_STR; + default: return 0; + } +} + +/* parse_percent_value(): parse after '%' */ + +static const char *parse_percent_value(const char *fmt, struct arg_parse_s *arg) +{ + int parse_phase = PARSE_PHASE_INITIAL; + int pos = 0; + + arg->flag = 0; + arg->digit_specify = 0; + + while (!(arg->type = type_specify(fmt[pos]))) + { + switch (parse_phase) + { + case PARSE_PHASE_INITIAL: + switch (fmt[pos]) + { + case '-': + if (arg->flag & ARGPARSE_FLAG_MINUS) + { + /* Double specified */ + + return NULL; + } + + arg->flag |= ARGPARSE_FLAG_MINUS; + if (arg->flag & ARGPARSE_FLAG_PLUS) + { + parse_phase = PARSE_PHASE_PLSMIN; + } + + pos++; + + break; + + case '+': + if (arg->flag & ARGPARSE_FLAG_PLUS) + { + /* Double specified */ + + return NULL; + } + + arg->flag |= ARGPARSE_FLAG_PLUS; + if (arg->flag & ARGPARSE_FLAG_MINUS) + { + parse_phase = PARSE_PHASE_PLSMIN; + } + + pos++; + + break; + + case '0': + arg->flag |= ARGPARSE_FLAG_ZFILL; + parse_phase = PARSE_PHASE_ZFILL; + pos++; + break; + + default: + if (fmt[pos] >= '1' && fmt[pos] <= '9') + { + parse_phase = PARSE_PHASE_DIGIT; + + /* no pos increment because digit detect in DIGIT phase */ + } + else + { + return NULL; + } + + break; + } /* switch (fmt[pos]) */ + + break; + + case PARSE_PHASE_PLSMIN : + switch (fmt[pos]) + { + case '0': + arg->flag |= ARGPARSE_FLAG_ZFILL; + parse_phase = PARSE_PHASE_ZFILL; + pos++; + break; + + default: + if (fmt[pos] >= '1' && fmt[pos] <= '9') + { + parse_phase = PARSE_PHASE_DIGIT; + + /* no pos increment because digit parse is done + * in PARSE_PHASE_DIGIT + */ + } + else + { + return NULL; + } + } + + break; + + case PARSE_PHASE_ZFILL : + if (fmt[pos] >= '1' && fmt[pos] <= '9') + { + parse_phase = PARSE_PHASE_DIGIT; + + /* no pos increment because digit parse is done + * in PARSE_PHASE_DIGIT + */ + } + else + { + return NULL; + } + + break; + + case PARSE_PHASE_DIGIT : + arg->digit_specify = fmt[pos] - '0'; + pos++; + while (fmt[pos] >= '0' && fmt[pos] <= '9') + { + arg->digit_specify = + arg->digit_specify * 10 + fmt[pos] - '0'; + pos++; + } + + parse_phase = PARSE_PHASE_DONE; + break; + + case PARSE_PHASE_DONE : + /* Should not enter here */ + + return NULL; + } + } /* while (!(arg->type = is_type_specify(fmt[pos]))) */ + + return &fmt[pos]; +} + +/* worker_vprintf(): parse and print string and variables */ + +static int worker_vprintf(const char *fmt, va_list va) +{ + int total_len = 0; + int val; + struct arg_parse_s arg; + const char *tmp; + + while (*fmt != '\0') + { + switch (*fmt) + { + case '%': + fmt++; + if (*fmt == '%') + { + lowputc(*fmt); total_len++; + } + else + { + arg.type = 0; + tmp = parse_percent_value(fmt, &arg); + if (tmp == NULL) + { + /* Format error is detected. + * Operate as normal string. + */ + + lowputc('%'); + total_len++; + fmt--; + } + else + { + /* Actual print argument */ + + switch (arg.type) + { + case VALPARSE_TYPE_CHAR: + arg.value.c = va_arg(va, int); + lowputc(arg.value.c); + total_len++; + break; + + case VALPARSE_TYPE_SINT: + val = va_arg(va, int); + if (val < 0) + { + arg.flag |= ARGPARSE_FLAG_NEGVAL; + arg.value.u = - val; + } + else + { + arg.value.u = val; + } + + total_len += print_int(&arg); + break; + + case VALPARSE_TYPE_UINT: + arg.value.u = va_arg(va, unsigned int); + total_len += print_int(&arg); + break; + + case VALPARSE_TYPE_HEXL: + arg.value.u = va_arg(va, unsigned int); + total_len += print_hex(&arg, 'a'); + break; + + case VALPARSE_TYPE_HEXH: + arg.value.u = va_arg(va, unsigned int); + total_len += print_hex(&arg, 'A'); + break; + + case VALPARSE_TYPE_PTR: + arg.value.u = va_arg(va, unsigned int); + if (arg.value.u) + { + arg.flag |= ARGPARSE_FLAG_ZFILL; + arg.digit_specify = 8; + total_len += print_hex(&arg, 'a'); + } + else + { + total_len += lowputs("(null)"); + } + + break; + + case VALPARSE_TYPE_STR: + arg.value.cp = va_arg(va, char *); + total_len += lowputs(arg.value.cp); + break; + } /* switch (arg.type) */ + + fmt = tmp; + } /* else of if (tmp == NULL) */ + } /* else of if (*fmt == '%') */ + + break; /* case '%': */ + + case '\n': + lowputc('\r'); + lowputc('\n'); + total_len++; + break; + + default: + lowputc(*fmt); + total_len++; + break; + } /* switch (*fmt) */ + + fmt++; + } + + return total_len; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/* For debug use only */ + +int printf(const char *fmt, ...) +{ + int ret; + va_list va; + + va_start(va, fmt); + ret = worker_vprintf(fmt, va); + va_end(va); + + return ret; +} + +int puts(const char *str) +{ + return lowputs(str); +} + +int putchar(const char c) +{ + lowputc(c); + + return (int)c; +} diff --git a/sdk/modules/audio/Makefile b/sdk/modules/audio/Makefile index 12d69f3dd..899e32d23 100644 --- a/sdk/modules/audio/Makefile +++ b/sdk/modules/audio/Makefile @@ -51,7 +51,6 @@ include container_format_lib/Make.defs AUDIODIR = $(SDKDIR)$(DELIM)modules$(DELIM)audio CXXFLAGS += ${INCDIR_PREFIX}$(AUDIODIR)$(DELIM)dsp_driver$(DELIM)include -CXXFLAGS += ${INCDIR_PREFIX}$(AUDIODIR) CXXFLAGS += ${INCDIR_PREFIX}$(AUDIODIR)$(DELIM)include CXXFLAGS += ${INCDIR_PREFIX}$(AUDIODIR)$(DELIM)components CXXFLAGS += ${INCDIR_PREFIX}$(AUDIODIR)$(DELIM)objects diff --git a/sdk/modules/audiolite/Kconfig b/sdk/modules/audiolite/Kconfig index c9f988e0f..5c06883a5 100644 --- a/sdk/modules/audiolite/Kconfig +++ b/sdk/modules/audiolite/Kconfig @@ -220,10 +220,46 @@ config AIDO_LITE_MP3DEC_SUBCORE_ELFNAME set "/mnt/sd0/mp3dec". To enable this option, needs to enable EXTERNALS_CMSIS, ASMP and ASMP_WORKER_LIBC -endif # end of if AUDIO_LITE_MP3DEC - endif # AUDIO_LITE_MP3DEC_SUBCORE_ELF +if AUDIO_LITE_MP3DEC_SUBCORE_SPK + +config AUDIO_LITE_MP3DEC_SUBCORE_SPK_BUILD + bool "Build mp3dec spk" + default n + ---help--- + Enable build SPK file named "mp3dec.spk" in sdk/modules/audiolite/worker/mp3dec directory. + If you want to use your built mp3dec.spk, you need flash it like + $ ./tools/flash.sh modules/audiolite/worker/mp3dec/mp3dec.spk + +endif # AUDIO_LITE_MP3DEC_SUBCORE_SPK + +if AUDIO_LITE_MP3DEC_SUBCORE_ELF || AUDIO_LITE_MP3DEC_SUBCORE_SPK_BUILD + +config AUDIO_LITE_MP3DEC_SUBCORE_DEBUG + bool "Enable Debug print in mo3dec Worker" + default n + ---help--- + Enable display debug message from mp3dec worker. This debug message pass to UART1. + And it is expected that the HW initialization has finished by main core. + If you want to change it from UART1 to others, modify it in a source code. + This makes that the worker takes long time to print information. So realtime playing + will be stopped. + +if AUDIO_LITE_MP3DEC_SUBCORE_DEBUG + +config AUDIO_LITE_MP3DEC_SUBCORE_DEBUG_DETAIL + bool "Enable print detail information of mo3dec Worker" + default n + ---help--- + Enable display buffer status and pointer. + +endif # AUDIO_LITE_MP3DEC_SUBCORE_DEBUG + +endif # AUDIO_LITE_MP3DEC_SUBCORE_ELF || AUDIO_LITE_MP3DEC_SUBCORE_SPK_BUILD + +endif # end of if AUDIO_LITE_MP3DEC + endmenu # MP3 Decorder Component endif # end of if AUDIO_LITE diff --git a/sdk/modules/audiolite/Makefile b/sdk/modules/audiolite/Makefile index f0f573219..d918fd810 100644 --- a/sdk/modules/audiolite/Makefile +++ b/sdk/modules/audiolite/Makefile @@ -37,8 +37,6 @@ # Set 1 FORACE_WORKER_BUILD when you want to make spk -FORCE_WORKER_BUILD = - MODNAME = audiolite CXXEXT = .cxx @@ -47,6 +45,8 @@ CXXSRCS += src/base/al_evthandler.cxx CXXSRCS += src/base/al_inputnode.cxx CXXSRCS += src/base/al_memalloc.cxx CXXSRCS += src/base/al_outputnode.cxx +CXXSRCS += src/base/al_thread.cxx +CXXSRCS += src/base/al_workercomp.cxx CXXSRCS += src/base/al_stream.cxx CXXSRCS += src/base/al_decoder.cxx CXXSRCS += src/base/al_worker.cxx @@ -66,7 +66,7 @@ CXXFLAGS += -I include -DBUILD_TGT_SUPERVISOR ifneq ($(CONFIG_AUDIO_LITE_MP3DEC_SUBCORE_ELF),) CSRCS += dummy.c -else ifeq ($(FORCE_WORKER_BUILD),1) +else ifeq ($(CONFIG_AUDIO_LITE_MP3DEC_SUBCORE_SPK_BUILD),y) CSRCS += dummy.c endif @@ -74,12 +74,11 @@ include $(SDKDIR)/modules/Module.mk .PHONY: build_mp3dec build_mp3dec: - @$(MAKE) -C worker/mp3dec TOPDIR="$(TOPDIR)" SDKDIR="$(SDKDIR)" APPDIR="$(APPDIR)" CROSSDEV=$(CROSSDEV) FORCE_BUILD=$(FORCE_WORKER_BUILD) + @$(MAKE) -C worker/mp3dec TOPDIR="$(TOPDIR)" SDKDIR="$(SDKDIR)" APPDIR="$(APPDIR)" CROSSDEV=$(CROSSDEV) dummy.c: build_mp3dec clean_mp3dec: - @$(MAKE) -C worker/mp3dec TOPDIR="$(TOPDIR)" SDKDIR="$(SDKDIR)" APPDIR="$(APPDIR)" CROSSDEV=$(CROSSDEV) FORCE_BUILD=$(FORCE_WORKER_BUILD) clean + @$(MAKE) -C worker/mp3dec TOPDIR="$(TOPDIR)" SDKDIR="$(SDKDIR)" APPDIR="$(APPDIR)" CROSSDEV=$(CROSSDEV) clean clean:: clean_mp3dec - diff --git a/sdk/modules/audiolite/src/base/al_component.cxx b/sdk/modules/audiolite/src/base/al_component.cxx index 619bd8925..efb46eb25 100644 --- a/sdk/modules/audiolite/src/base/al_component.cxx +++ b/sdk/modules/audiolite/src/base/al_component.cxx @@ -422,7 +422,17 @@ void audiolite_component::on_data() if (_outnum > 0) { - _outs[0]->push_data(mem); + if (mem->get_storedsize() != 0) + { + _outs[0]->push_data(mem); + } + else + { + printf("[AudioLite] %s(%d) : ZERO size memory is pushed\n" + " This might be BUG. \n" + " Check it if it is expected\n", + __func__, __LINE__); + } } mem->release(); @@ -561,9 +571,10 @@ audiolite_outputnode *audiolite_component::get_output(int id) return NULL; } -int audiolite_component::bind(audiolite_component *cmp) +audiolite_component *audiolite_component::bind(audiolite_component *cmp) { - return bind(cmp->get_input(), 0); + bind(cmp->get_input(), 0); + return cmp; } int audiolite_component::bind(audiolite_inputnode *in, int outid) @@ -607,6 +618,42 @@ int audiolite_component::unbindall() return 0; } +int audiolite_component::start() +{ + if (_innum != 0) + { + return -ENOTSUP; + } + + return start((audiolite_inputnode *)NULL); +} + +void audiolite_component::stop() +{ + if (_innum == 0) + { + stop((audiolite_inputnode *)NULL); + } +} + +void audiolite_component::suspend() +{ + if (_innum == 0) + { + stop((audiolite_inputnode *)NULL); + } +} + +int audiolite_component::resume() +{ + if (_innum != 0) + { + return -ENOTSUP; + } + + return start((audiolite_inputnode *)NULL); +} + /*********************************************** * Static Protected Class audiolite_component Methods ***********************************************/ diff --git a/sdk/modules/audiolite/src/base/al_decoder.cxx b/sdk/modules/audiolite/src/base/al_decoder.cxx index 346b1a7cd..d4e783f11 100644 --- a/sdk/modules/audiolite/src/base/al_decoder.cxx +++ b/sdk/modules/audiolite/src/base/al_decoder.cxx @@ -46,8 +46,8 @@ audiolite_decoder::audiolite_decoder(const char *name, int prio, int stack_sz) - : audiolite_source(0, 1), - _stream(NULL), _prio(prio), _stacksz(stack_sz), + : audiolite_component(0, 1), _stream(NULL), + _omempool(NULL), _prio(prio), _stacksz(stack_sz), _tid(-1), _tname(name), _isplay(false), _ispause(false), _is_thrdrun(false) { @@ -100,6 +100,11 @@ void audiolite_decoder::stop_thread() _pool->disable_pool(); } + if (_omempool) + { + _omempool->disable_pool(); + } + mossfw_thread_join(&_tid); _tid = -1; } diff --git a/sdk/modules/audiolite/src/base/al_evthandler.cxx b/sdk/modules/audiolite/src/base/al_evthandler.cxx index d584b7853..acea5d7b2 100644 --- a/sdk/modules/audiolite/src/base/al_evthandler.cxx +++ b/sdk/modules/audiolite/src/base/al_evthandler.cxx @@ -47,6 +47,8 @@ MOSSFW_DATA_TYPENAME_AUDIO + \ MOSSFW_DATA_TYPEARRAY_ARRAY) +#define STRINGCASE(e) case AL_EVENT_##e: return #e; + /**************************************************************************** * class: audiolite_evthandler ****************************************************************************/ @@ -62,7 +64,7 @@ SINGLETON_INST(audiolite_evthandler); ***********************************************/ audiolite_evthandler::audiolite_evthandler(int memnum) - : _fs(0), _chnum(0), _bitwidth(0), _listen(NULL) + : _fs(48000), _chnum(2), _bitwidth(16), _listen(NULL) { _pool = new audiolite_mempoolsysmsg; _pool->create_instance(memnum); @@ -162,3 +164,38 @@ void audiolite_eventdestroy(void) { audiolite_evthandler::terminate_instance(); } + +const char *audiolite_strevent(int evt) +{ + switch (evt) + { + STRINGCASE(OVERFLOW) + STRINGCASE(UNDERFLOW) + STRINGCASE(ILLIGALSTREAM) + STRINGCASE(UNSUPPORTFMT) + STRINGCASE(DECODEDONE) + STRINGCASE(STREAMDONE) + STRINGCASE(PLAYSTARTED) + STRINGCASE(PLAYSTOPPED) + STRINGCASE(RECORDSTARTED) + STRINGCASE(RECORDSTOPPED) + STRINGCASE(PLAYPAUSED) + STRINGCASE(PLAYRESUMED) + STRINGCASE(RECORDPAUSED) + STRINGCASE(RECORDRESUMED) + STRINGCASE(DRVERROR) + STRINGCASE(INVALIDSYSPARAM) + STRINGCASE(STOPOUTPUT) + STRINGCASE(STOPINPUT) + STRINGCASE(INITERROR) + STRINGCASE(SENDERROR) + STRINGCASE(MP3FRAMEINFO) + STRINGCASE(MP3DECWORKEREND) + STRINGCASE(UNKNOWN) + STRINGCASE(MP3DECERROR) + STRINGCASE(MP3DEC_WRONGTYPE) + STRINGCASE(WRONGVERSION) + default: + return "not event id..."; + } +} diff --git a/sdk/modules/audiolite/src/base/al_memalloc.cxx b/sdk/modules/audiolite/src/base/al_memalloc.cxx index 7fddef8c1..1012ffb3e 100644 --- a/sdk/modules/audiolite/src/base/al_memalloc.cxx +++ b/sdk/modules/audiolite/src/base/al_memalloc.cxx @@ -416,7 +416,7 @@ audiolite_mem *audiolite_mempoolapbuf::allocate(bool blocking) { int qsz; audiolite_memapbuf *ret = NULL; - dq_entry_t *tmp; + dq_entry_t *tmp = NULL; mossfw_lock_take(&_lock); @@ -431,11 +431,17 @@ audiolite_mem *audiolite_mempoolapbuf::allocate(bool blocking) measure_start(); } - tmp = dq_remfirst(&_free_mem); - while (_pool_enable && blocking && tmp == NULL) + if (_pool_enable) { - mossfw_condition_wait(&_cond, &_lock); tmp = dq_remfirst(&_free_mem); + while (_pool_enable && blocking && tmp == NULL) + { + mossfw_condition_wait(&_cond, &_lock); + if (_pool_enable) + { + tmp = dq_remfirst(&_free_mem); + } + } } update_remain(qsz); @@ -473,6 +479,16 @@ void audiolite_mempoolapbuf::enable_pool() mossfw_lock_give(&_lock); } +int audiolite_mempoolapbuf::remaining() +{ + int ret; + mossfw_lock_take(&_lock); + ret = dq_count(&_free_mem); + mossfw_lock_give(&_lock); + + return ret; +} + /**************************************************************************** * class: audiolite_sysmsg ****************************************************************************/ @@ -639,3 +655,13 @@ void audiolite_mempoolsysmsg::enable_pool() mossfw_condition_notice(&_cond); mossfw_lock_give(&_lock); } + +int audiolite_mempoolsysmsg::remaining() +{ + int ret; + mossfw_lock_take(&_lock); + ret = dq_count(&_free_mem); + mossfw_lock_give(&_lock); + + return ret; +} diff --git a/sdk/modules/audiolite/src/base/al_stream.cxx b/sdk/modules/audiolite/src/base/al_stream.cxx index 13dff585f..9b7117cd2 100644 --- a/sdk/modules/audiolite/src/base/al_stream.cxx +++ b/sdk/modules/audiolite/src/base/al_stream.cxx @@ -181,15 +181,21 @@ int audiolite_filestream::receive_data(audiolite_mem *mem, int sz = mem->get_fullsize() - ofst; int ret = 0; + mem->set_storedsize(0); if (_fp && sz > 0) { ret = fread(&data[ofst], 1, sz, _fp); - if (sz != ret) + if (feof(_fp)) { mem->set_eof(); + fclose(_fp); + _fp = NULL; } - mem->set_storedsize(ret); + if (ret >= 0) + { + mem->set_storedsize(ret); + } } return ret; @@ -200,12 +206,11 @@ int audiolite_filestream::send_data(audiolite_mem *mem, { char *data = (char *)mem->get_data(); int sz = mem->get_storedsize() - ofst; - int ret = 0; + int ret = -EINVAL; if (_fp && sz > 0) { - ret = fwrite(&data[ofst], sz, 1, _fp); - ret = ret == 1 ? sz : ret; + ret = fwrite(&data[ofst], 1, sz, _fp); } return ret; diff --git a/sdk/modules/audiolite/src/base/al_thread.cxx b/sdk/modules/audiolite/src/base/al_thread.cxx new file mode 100644 index 000000000..a9b3b0310 --- /dev/null +++ b/sdk/modules/audiolite/src/base/al_thread.cxx @@ -0,0 +1,96 @@ +#include +#include + +audiolite_thread::audiolite_thread(audiolite_runnable_if *runnable, + void *runnable_arg, + int prio, int stacksz, + const char *thdname) + : _runnable(runnable), _runnable_arg(runnable_arg), + _tid(-1), _prio(prio), _stacksz(stacksz), _is_thrdrun(false) +{ + if (thdname) + { + strncpy(_tname, thdname, AL_THREAD_NAMEMAX - 1); + } + else + { + _tname[0] = '\0'; + } +} + +audiolite_thread::~audiolite_thread() +{ + stop(); +} + +bool audiolite_thread::set_runnable(audiolite_runnable_if *runnable, + void *runnable_arg) +{ + if (!_is_thrdrun) + { + _runnable = runnable; + _runnable_arg = runnable_arg; + return true; + } + + return false; +} + +bool audiolite_thread::start() +{ + int ret = false; + if (!_is_thrdrun && _runnable) + { + _is_thrdrun = true; + ret = mossfw_create_thread_attr(&_tid, + audiolite_thread::running_thread, + this, + _prio, _stacksz); + if (ret == 0) + { + ret = true; + if (_tname[0]) + { + pthread_setname_np(_tid, _tname); + } + } + else + { + _tid = -1; + _is_thrdrun = false; + } + } + + return ret; +} + +void audiolite_thread::stop() +{ + if (_is_thrdrun) + { + _is_thrdrun = false; + _runnable->before_stop(_runnable_arg); + mossfw_thread_join(&_tid); + _tid = -1; + } +} + +void *audiolite_thread::running_thread(void *arg) +{ + int ret; + audiolite_thread *thiz = (audiolite_thread *)arg; + + while (thiz->_is_thrdrun && + !thiz->_runnable->before_start(thiz->_runnable_arg)) + { + usleep(10 * 1000); /* Wait and yeild */ + } + + ret = 1; + while (thiz->_is_thrdrun && ret) + { + ret = thiz->_runnable->run(thiz->_runnable_arg); + } + + return NULL; +} diff --git a/sdk/modules/audiolite/src/base/al_worker.cxx b/sdk/modules/audiolite/src/base/al_worker.cxx index 0bdec9a5d..d9a24e3fc 100644 --- a/sdk/modules/audiolite/src/base/al_worker.cxx +++ b/sdk/modules/audiolite/src/base/al_worker.cxx @@ -126,6 +126,32 @@ audiolite_memapbuf *audiolite_workermemq::pop() return mem; } +audiolite_memapbuf *audiolite_workermemq::pop(unsigned char *adr) +{ + audiolite_memapbuf *mem = NULL; + dq_entry_t *tmp; + + mossfw_lock_take(&_lock); + + for (tmp = dq_peek(&_mem_proc); tmp; tmp = tmp->blink) + { + mem = audiolite_memapbuf::local_cast(tmp); + if (adr == alworker_addr_convert(mem->get_data())) + { + dq_rem(tmp, &_mem_proc); + break; + } + mem = NULL; + } + + mossfw_condition_notice(&_cond); + mossfw_lock_give(&_lock); + + al_dinfo("[%08x] poped with addr (%08x) %d : %08x\n", + this, adr, dq_count(&_mem_proc), mem); + return mem; +} + /**************************************************************************** * class: audiolite_worker ****************************************************************************/ diff --git a/sdk/modules/audiolite/src/base/al_workercmd.cxx b/sdk/modules/audiolite/src/base/al_workercmd.cxx index 1186bd676..4662d4f72 100644 --- a/sdk/modules/audiolite/src/base/al_workercmd.cxx +++ b/sdk/modules/audiolite/src/base/al_workercmd.cxx @@ -152,6 +152,21 @@ int alworker_send_start(al_wtask_t *wtask) return ret; } +int alworker_send_stop(al_wtask_t *wtask) +{ + int ret; + al_comm_msghdr_t hdr; + al_comm_msgopt_t opt; + + hdr.grp = AL_COMM_MESSAGE_SYS; + hdr.type = AL_COMM_MSGTYPE_ASYNC; + hdr.code = AL_COMM_MSGCODESYS_STOP; + hdr.opt = 0; + + ret = al_send_message(wtask, hdr, &opt); + return ret; +} + int alworker_send_term(al_wtask_t *wtask) { int ret; @@ -167,6 +182,17 @@ int alworker_send_term(al_wtask_t *wtask) return ret; } +int alworker_send_resp(al_wtask_t *wtask, al_comm_msghdr_t hdr, int ret) +{ + al_comm_msgopt_t opt; + + hdr.type = AL_COMM_MSGTYPE_RESP; + hdr.opt = ret; + + ret = al_send_message(wtask, hdr, &opt); + return ret; +} + int alworker_inject_omem(al_wtask_t *wtask, audiolite_mem *mem) { return send_oframe(wtask, mem->get_data(), mem->get_fullsize()); @@ -175,6 +201,6 @@ int alworker_inject_omem(al_wtask_t *wtask, audiolite_mem *mem) int alworker_inject_imem(al_wtask_t *wtask, audiolite_mem *mem) { return send_iframe(wtask, mem->get_data(), - mem->get_fullsize(), + mem->get_storedsize(), mem->is_eof()); } diff --git a/sdk/modules/audiolite/src/base/al_workercomp.cxx b/sdk/modules/audiolite/src/base/al_workercomp.cxx new file mode 100644 index 000000000..1fba89d14 --- /dev/null +++ b/sdk/modules/audiolite/src/base/al_workercomp.cxx @@ -0,0 +1,320 @@ +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include + +/**************************************************************************** + * Class Method Functions + ****************************************************************************/ + +void audiolite_stdworker_msglistener::push_data(audiolite_workercomp *wcomp, + audiolite_memapbuf *mem) +{ + wcomp->push_data(mem); +} + +int audiolite_stdworker_msglistener::get_inqsize(audiolite_workercomp *wcomp) +{ + return wcomp->_inq.get_qsize(); +} + +int audiolite_stdworker_msglistener::get_outqsize(audiolite_workercomp *wcomp) +{ + return wcomp->_outq.get_qsize(); +} + +audiolite_memapbuf *audiolite_stdworker_msglistener::allocate(audiolite_workercomp *wcomp) +{ + return (audiolite_memapbuf *)wcomp->_pool->allocate(); +} + +audiolite_workercomp::audiolite_workercomp(const char *workername, + int inqsz, int outqsz, + int inputnum, int outputnum, + int depth, int prio, int stack_sz) + : audiolite_component(inputnum, outputnum, depth, true, prio, stack_sz), + _inq(inqsz), _outq(outqsz), _worker_booted(false), + _worker_terminated(true), _lsnr(NULL), _thd(this, this, 105, 2048) +{ + if (workername != NULL) + { + strncpy(_workerspk, workername, WORKERCOMP_SPKNAMESZ - 1); + } + + _worker.set_msghandler(audiolite_workercomp::handle_message, this); +} + +audiolite_workercomp::~audiolite_workercomp() +{ +} + +int audiolite_workercomp::handle_message(al_comm_msghdr_t hdr, + al_comm_msgopt_t *opt, + void *arg) +{ + int ret = 0; + audiolite_workercomp *thiz = (audiolite_workercomp *)arg; + audiolite_stdworker_msglistener *listener = thiz->_lsnr; + al_wtask_t *wtask = thiz->_worker.getwtask(); + audiolite_memapbuf *mem; + audiolite_memapbuf *nmem; + + if (listener == NULL) + { + return -1; + } + + if (CHECK_HDR(hdr, SYS, SYS_BOOT)) + { + listener->bootup(thiz, wtask, hdr.opt, opt->addr); + thiz->_worker_booted = true; + } + else if (CHECK_HDR(hdr, SYS, SYS_ERR)) + { + listener->error(thiz, wtask, hdr.opt, opt->errcode); + } + else if (CHECK_HDR(hdr, SYS, SYS_PLAY)) + { + /* Just received. Do nothing. */ + } + else if (CHECK_HDR(hdr, SYS, SYS_PARAM)) + { + /* Just received. Do nothing. */ + } + else if (CHECK_HDR(hdr, SYS, SYS_DBG)) + { + listener->debug(thiz, wtask, hdr.opt); + } + else if (CHECK_HDR(hdr, INST, INST_INFO)) + { + listener->info(thiz, wtask, hdr.opt, opt->dec_chs, opt->hz, + opt->dec_layer, opt->dec_kbps); + } + else if (CHECK_HDR(hdr, INST, INST_DONE)) + { + listener->done(thiz, wtask, hdr.opt); + } + else if (CHECK_HDR(hdr, SYS, SYS_TERM)) + { + listener->term(thiz); + thiz->_worker_terminated = true; + + /* Release all memory */ + + for (mem = thiz->_inq.pop(); mem; mem = thiz->_inq.pop()) + { + mem->release(); + } + + for (mem = thiz->_outq.pop(); mem; mem = thiz->_outq.pop()) + { + mem->release(); + } + + ret = -1; + } + else if (CHECK_HDR(hdr, FMEM, MEM_RELEASE)) + { + mem = thiz->_inq.pop(opt->addr); + if (mem) + { + nmem = listener->release_inmem(thiz, wtask, mem, opt->size); + mem->release(); + if (nmem) + { + thiz->_inq.push(nmem); + alworker_inject_imem(wtask, nmem); + } + } + } + else if (CHECK_HDR(hdr, OMEM, MEM_RELEASE)) + { + mem = thiz->_outq.pop(opt->addr); + if (mem) + { + if (opt->eof == 1) + { + mem->set_eof(); + } + else + { + mem->clear_eof(); + } + + mem->set_storedsize(opt->size); + nmem = listener->release_outmem(thiz, wtask, mem); + mem->release(); + if (nmem) + { + thiz->_outq.push(nmem); + alworker_inject_omem(wtask, nmem); + } + } + } + else if (hdr.grp == AL_COMM_MESSAGE_USER) + { + listener->usermsg(thiz, wtask, hdr, opt); + } + else if (hdr.u32 != AL_COMM_NO_MSG) + { + thiz->publish_event(AL_EVENT_UNKNOWN, hdr.u32); + } + + if (hdr.type == AL_COMM_MSGTYPE_SYNC) + { + alworker_send_resp(wtask, hdr, ret); + } + + return ret; +} + +void audiolite_workercomp::on_data() +{ + audiolite_memapbuf *mem = (audiolite_memapbuf *)pop_data(); + + if (mem) + { + if (_worker_booted == true) + { + _inq.push(mem); + alworker_inject_imem(_worker.getwtask(), mem); + } + else + { + mem->release(); + } + } +} + +int audiolite_workercomp::start_worker() +{ + int ret = OK; + char thdname[WORKERCOMP_SPKNAMESZ + 4]; + + if (_lsnr == NULL) + { + ret = ERROR; + } + else if (!_worker_booted) + { + ret = OK; + snprintf(thdname, WORKERCOMP_SPKNAMESZ + 3, "%ssvr", _workerspk); + if (_pool) + { + /* If output memory pool is exist, injection thread is needed */ + + if (_thd.start()) + { + _pool->enable_pool(); + } + else + { + ret = ERROR; + } + } + + if (ret == OK) + { + _inq.enable(); + _outq.enable(); + ret = _worker.bringup_worker(_workerspk, true, + thdname, 105, 2048); + if (ret != OK) + { + if (_pool) + { + _pool->disable_pool(); + _thd.stop(); + } + + _inq.disable(); + _outq.disable(); + } + } + } + + return ret; +} + +void audiolite_workercomp::stop_worker() +{ + if (_pool) + { + _pool->disable_pool(); + } + + _inq.disable(); + + if (_worker_booted) + { + _thd.stop(); + + _worker_booted = false; + _worker_terminated = false; + alworker_send_term(_worker.getwtask()); + while (_worker_terminated == false) + { + usleep(1); + } + } + + _worker.terminate_worker(); + _outq.disable(); +} + +int audiolite_workercomp::on_starting(audiolite_inputnode *inode, + audiolite_outputnode *onode) +{ + return start_worker(); +} + +void audiolite_workercomp::on_canceled(audiolite_inputnode *inode, + audiolite_outputnode *onode) +{ + stop_worker(); +} + +void audiolite_workercomp::on_stopping(audiolite_inputnode *inode, + audiolite_outputnode *onode) +{ + stop_worker(); +} + +bool audiolite_workercomp::before_start(void *arg) +{ + audiolite_workercomp *thiz = (audiolite_workercomp *)arg; + + return thiz->_worker_booted; +} + +int audiolite_workercomp::run(void *arg) +{ + audiolite_workercomp *thiz = (audiolite_workercomp *)arg; + audiolite_memapbuf *mem; + + if (thiz->_worker_booted) + { + mem = (audiolite_memapbuf *)_pool->allocate(); + + if (mem) + { + thiz->_outq.push(mem); + alworker_inject_omem(thiz->_worker.getwtask(), mem); + } + else + { + usleep(1); /* Yield */ + } + } + + return 1; +} + +void audiolite_workercomp::before_stop(void *arg) +{ +} diff --git a/sdk/modules/audiolite/src/components/al_inputcomp.cxx b/sdk/modules/audiolite/src/components/al_inputcomp.cxx index 93da1b117..ce8790c07 100644 --- a/sdk/modules/audiolite/src/components/al_inputcomp.cxx +++ b/sdk/modules/audiolite/src/components/al_inputcomp.cxx @@ -58,7 +58,7 @@ ****************************************************************************/ audiolite_inputcomp::audiolite_inputcomp(bool isi2s) : - audiolite_source(0,1), _tid(-1), _is_running(false), _is_stopped(true) + audiolite_component(0,1), _tid(-1), _is_running(false), _is_stopped(true) { if (isi2s) { @@ -152,13 +152,26 @@ int audiolite_inputcomp::on_starting(audiolite_inputnode *inode, return -1; } + ret = audiolite_component::on_starting(inode, onode); + + al_ddebug("Leave\n"); + return ret; +} + +void audiolite_inputcomp::on_started(audiolite_inputnode *inode, + audiolite_outputnode *onode) +{ + int ret; + + al_ddebug("Entry\n"); + _pool->enable_pool(); ret = _driver->start(samplingrate(), samplebitwidth(), channels()); if (ret != 0) { publish_event(AL_EVENT_DRVERROR, (unsigned long)ret); - return -1; + return; } ret = start_thread(); @@ -166,19 +179,9 @@ int audiolite_inputcomp::on_starting(audiolite_inputnode *inode, { publish_event(AL_EVENT_INITERROR, (unsigned long)ret); _driver->stop(); - return -1; + return; } - ret = audiolite_component::on_starting(inode, onode); - - al_ddebug("Leave\n"); - return ret; -} - -void audiolite_inputcomp::on_started(audiolite_inputnode *inode, - audiolite_outputnode *onode) -{ - al_ddebug("Entry\n"); audiolite_component::on_started(inode, onode); al_ddebug("Leave\n"); } @@ -195,8 +198,8 @@ void audiolite_inputcomp::on_stopping(audiolite_inputnode *inode, audiolite_outputnode *onode) { al_ddebug("Enter\n"); + audiolite_component::on_stopping(inode, onode); notice_stop(true); - audiolite_component::on_stop(inode, onode); } void audiolite_inputcomp::on_stop(audiolite_inputnode *inode, @@ -215,12 +218,18 @@ void audiolite_inputcomp::on_popeddata(FAR struct ap_buffer_s *apb) audiolite_memapbuf *mem = audiolite_memapbuf::local_cast((dq_entry_t *)apb); - mem->set_fs(samplingrate()); - mem->set_channels(channels()); - mem->set_storedsize(mem->get_fullsize()); - - _outs[0]->push_data(mem); - mem->release(); + if (mem) + { + mem->set_fs(samplingrate()); + mem->set_channels(channels()); + mem->set_storedsize(mem->get_fullsize()); + _outs[0]->push_data(mem); + mem->release(); + } + else + { + al_ddebug("Error no memory on audiolite_inputcomp::on_popeddata\n"); + } } void audiolite_inputcomp::on_stopped(void) @@ -257,7 +266,11 @@ void *audiolite_inputcomp::inject_worker(void *arg) } else { - thiz->_driver->enqueue_buffer(mem->get_raw_abuf()); + if (thiz->_driver->enqueue_buffer(mem->get_raw_abuf()) != OK) + { + mem->release(); + usleep(1); + } } } } @@ -265,25 +278,3 @@ void *audiolite_inputcomp::inject_worker(void *arg) return NULL; } - -/* Inherited member functions from audiolite_source */ - -int audiolite_inputcomp::start() -{ - return audiolite_component::start((audiolite_inputnode *)NULL); -} - -void audiolite_inputcomp::stop() -{ - audiolite_component::stop((audiolite_inputnode *)NULL); -} - -void audiolite_inputcomp::pause() -{ - audiolite_component::stop((audiolite_inputnode *)NULL); -} - -int audiolite_inputcomp::resume() -{ - return audiolite_component::start((audiolite_inputnode *)NULL); -} diff --git a/sdk/modules/audiolite/src/components/al_mp3dec.cxx b/sdk/modules/audiolite/src/components/al_mp3dec.cxx index f27b2b9a1..344bb6380 100644 --- a/sdk/modules/audiolite/src/components/al_mp3dec.cxx +++ b/sdk/modules/audiolite/src/components/al_mp3dec.cxx @@ -74,7 +74,7 @@ void audiolite_mp3dec::decode_runner() while (_is_thrdrun) { - if (_isplay) + if (_isplay && _worker_booted) { audiolite_memapbuf *mem = (audiolite_memapbuf *)_omempool->allocate(); @@ -88,6 +88,12 @@ void audiolite_mp3dec::decode_runner() * It will be done after finishing decode. */ } + else + { + /* Yeild */ + + usleep(10 * 1000); + } } else { @@ -116,7 +122,7 @@ int audiolite_mp3dec::handle_mesage(al_comm_msghdr_t hdr, mem = thiz->_inq.pop(); if (mem) { - if (thiz->_frame_eof) + if (thiz->_frame_eof || thiz->_worker_booted != true) { mem->release(); } @@ -144,8 +150,17 @@ int audiolite_mp3dec::handle_mesage(al_comm_msghdr_t hdr, mem = thiz->_outq.pop(); if (mem) { - mem->set_storedsize(opt->size); - thiz->_outs[0]->push_data(mem); + if (thiz->_worker_booted) + { + mem->set_storedsize(opt->size); + mem->clear_eof(); + if (opt->eof != 0) + { + mem->set_eof(); + } + + thiz->_outs[0]->push_data(mem); + } mem->release(); } } @@ -163,6 +178,7 @@ int audiolite_mp3dec::handle_mesage(al_comm_msghdr_t hdr, { al_dinfo("TERM\n"); thiz->publish_event(AL_EVENT_MP3DECWORKEREND, 0); + thiz->_worker_terminated = true; ret = -1; } else if (CHECK_HDR(hdr, SYS, SYS_PARAM)) @@ -184,7 +200,7 @@ int audiolite_mp3dec::handle_mesage(al_comm_msghdr_t hdr, if (hdr.opt != AL_MP3DECWORKER_VERSION) { - thiz->publish_event(AL_EVENT_MP3DEC_WRONGVER, hdr.opt); + thiz->publish_event(AL_EVENT_WRONGVERSION, hdr.opt); return 0; } @@ -216,18 +232,9 @@ int audiolite_mp3dec::handle_mesage(al_comm_msghdr_t hdr, } } - for (int i = 0; i < thiz->_outq.get_qsize(); i++) - { - mem = (audiolite_memapbuf *)thiz->_omempool->allocate(); - if (mem) - { - thiz->_outq.push(mem); - alworker_inject_omem(thiz->_worker.getwtask(), mem); - } - } - alworker_send_startframe(thiz->_worker.getwtask()); alworker_send_start(thiz->_worker.getwtask()); + thiz->_worker_booted = true; /* This makes start injection of omem */ } else if (CHECK_HDR(hdr, SYS, SYS_ERR)) { @@ -243,7 +250,7 @@ int audiolite_mp3dec::handle_mesage(al_comm_msghdr_t hdr, } else { - thiz->publish_event(AL_EVENT_MP3DECUNKNOWNEVT, hdr.u32); + thiz->publish_event(AL_EVENT_UNKNOWN, hdr.u32); } return ret; @@ -252,9 +259,10 @@ int audiolite_mp3dec::handle_mesage(al_comm_msghdr_t hdr, audiolite_mp3dec::audiolite_mp3dec() : audiolite_decoder("mp3decomem", CONFIG_ALMP3DEC_INJECTPRIO, CONFIG_ALMP3DEC_INJECTSTACK), - _omempool(NULL), _worker(), + _worker(), _inq(SPRMP3_FRAMEMEM_QSIZE / 2), - _outq(SPRMP3_OUTMEM_QSIZE / 2), _frame_eof(false) + _outq(SPRMP3_OUTMEM_QSIZE / 2), _frame_eof(false), + _worker_booted(false), _worker_terminated(true) { _worker.set_msghandler(audiolite_mp3dec::handle_mesage, this); } @@ -291,8 +299,23 @@ int audiolite_mp3dec::stop_decode() { _pool->disable_pool(); } + _inq.disable(); - _worker.terminate_worker(); + + if (_worker_booted) + { + _worker_booted = false; + + _worker_terminated = false; + alworker_send_term(_worker.getwtask()); + while (_worker_terminated == false) + { + usleep(1); + } + + _worker.terminate_worker(); + } + _outq.disable(); return OK; diff --git a/sdk/modules/audiolite/src/components/al_outputcomp.cxx b/sdk/modules/audiolite/src/components/al_outputcomp.cxx index 9fe41ffc0..82a0ee0cd 100644 --- a/sdk/modules/audiolite/src/components/al_outputcomp.cxx +++ b/sdk/modules/audiolite/src/components/al_outputcomp.cxx @@ -59,7 +59,8 @@ audiolite_outputcomp::audiolite_outputcomp(bool is_sub) : audiolite_component(1,0, 16, true, CONFIG_ALOUTCOMP_PRIO, - CONFIG_ALOUTCOMP_STACKSZ) + CONFIG_ALOUTCOMP_STACKSZ), + enqueue_enable(false) { set_operatorname("outputcomp"); if (is_sub) @@ -96,10 +97,20 @@ int audiolite_outputcomp::set_volume(int vol) void audiolite_outputcomp::on_data() { audiolite_memapbuf *mem = - (audiolite_memapbuf *)_ins[0]->pop_data(NULL); - if (_driver->enqueue_buffer(mem->get_raw_abuf()) != OK) + (audiolite_memapbuf *)pop_data(); + if (mem) { - mem->release(); + if (enqueue_enable) + { + if (_driver->enqueue_buffer(mem->get_raw_abuf()) != OK) + { + mem->release(); + } + } + else + { + mem->release(); + } } } @@ -109,6 +120,7 @@ int audiolite_outputcomp::on_starting(audiolite_inputnode *inode, int ret; audiolite_component::on_starting(inode, onode); + enqueue_enable = true; _driver->set_listener(this); ret = _driver->start(samplingrate(), samplebitwidth(), channels()); if (ret != 0) @@ -129,6 +141,7 @@ void audiolite_outputcomp::on_started(audiolite_inputnode *inode, void audiolite_outputcomp::on_canceled(audiolite_inputnode *inode, audiolite_outputnode *onode) { + enqueue_enable = false; _driver->stop(); audiolite_component::on_canceled(inode, onode); } @@ -136,6 +149,7 @@ void audiolite_outputcomp::on_canceled(audiolite_inputnode *inode, void audiolite_outputcomp::on_stop(audiolite_inputnode *inode, audiolite_outputnode *onode) { + enqueue_enable = false; _driver->stop(); audiolite_component::on_stop(inode, onode); } @@ -152,7 +166,6 @@ void audiolite_outputcomp::on_pusheddata(FAR struct ap_buffer_s *apb) void audiolite_outputcomp::on_stopped(void) { - _driver->stop(); publish_event(AL_EVENT_STOPOUTPUT, 0); } diff --git a/sdk/modules/audiolite/src/components/al_wavenc.cxx b/sdk/modules/audiolite/src/components/al_wavenc.cxx index a15379706..ececf4d42 100644 --- a/sdk/modules/audiolite/src/components/al_wavenc.cxx +++ b/sdk/modules/audiolite/src/components/al_wavenc.cxx @@ -134,7 +134,12 @@ void audiolite_wavenc::on_data() int ret; int wsize = 0; audiolite_memapbuf *mem = - (audiolite_memapbuf *)_ins[0]->pop_data(NULL); + (audiolite_memapbuf *)pop_data(); + + if (mem == NULL) + { + return; + } mossfw_lock_take(&_lock); while (_stream->has_file() && wsize < mem->get_storedsize()) @@ -153,11 +158,6 @@ void audiolite_wavenc::on_data() mossfw_lock_give(&_lock); - if (!_stream->has_file()) - { - return; - } - mem->release(); _crnt_sz += wsize; @@ -172,13 +172,22 @@ void audiolite_wavenc::on_data() int audiolite_wavenc::on_starting(audiolite_inputnode *inode, audiolite_outputnode *onode) { - return _stream != NULL ? 0 : -1; + int ret = -1; + if (_stream) + { + create_wav_file(); + if (_stream->has_file()) + { + ret = 0; + } + } + + return ret; } void audiolite_wavenc::on_started(audiolite_inputnode *inode, audiolite_outputnode *onode) { - create_wav_file(); audiolite_encoder::on_started(inode, onode); } diff --git a/sdk/modules/audiolite/worker/common/alworker_comm.c b/sdk/modules/audiolite/worker/common/alworker_comm.c index 166ed712c..a4267766b 100644 --- a/sdk/modules/audiolite/worker/common/alworker_comm.c +++ b/sdk/modules/audiolite/worker/common/alworker_comm.c @@ -1,5 +1,5 @@ /**************************************************************************** - * modules/audiolite/worker/mp3dec/al_comm_comm.c + * modules/audiolite/worker/common/alworker_comm.c * * Copyright 2023 Sony Semiconductor Solutions Corporation * @@ -81,7 +81,9 @@ void *alworker_addr_convert(void *a) int initialize_alworker(al_wtask_t *inst, const char *dspfname, bool is_spk) { +#ifndef BUILD_TGT_ASMPWORKER int ret; +#endif key_t key = AL_COMM_MQ_NAMESEND; cpuid_t cid = 0; @@ -231,5 +233,6 @@ int al_send_message(al_wtask_t *inst, msg->hdr.u32 = hdr.u32; memcpy(&msg->opt, opt, sizeof(al_comm_msgopt_t)); - return mpmq_send(&inst->mqsend, msg->hdr.type, (uint32_t)msg); + while (mpmq_send(&inst->mqsend, msg->hdr.type, (uint32_t)msg) != OK); + return OK; } diff --git a/sdk/modules/audiolite/worker/common/alworker_commfw.c b/sdk/modules/audiolite/worker/common/alworker_commfw.c new file mode 100644 index 000000000..dbcaf0073 --- /dev/null +++ b/sdk/modules/audiolite/worker/common/alworker_commfw.c @@ -0,0 +1,777 @@ +/**************************************************************************** + * modules/audiolite/worker/mp3dec/sprmp3_msghandler.c + * + * Copyright 2023 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "audiolite/alworker_comm.h" +#include "alworker_commfw.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef ALWORKER_COMMFW_DEBUG +# define ALWORKER_TRACE() printf("[WORKER] %s(%d)\n", __func__, __LINE__) +# define ALWORKER_DMSG(...) do { \ + printf("[WORKER] %s(%d) : ", __func__, __LINE__); \ + printf(__VA_ARGS__); \ + }while(0) +#else +# define ALWORKER_TRACE() +# define ALWORKER_DMSG(...) +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +static al_wtask_t g_worker_task; +static alcommfw_cbs_t g_cbs; + +/**************************************************************************** + * Private functions + ****************************************************************************/ + +/*** name: release_allmem */ + +static void release_allmem(alworker_insthead_t *inst) +{ + memblk_t *mem; +#if CONF_WORKER_IMEMMAX > 0 + while ((mem = TAKE_IMEM(inst)) != NULL) + { + alworker_release_imem(inst, 0, mem); + } +#endif + +#if CONF_WORKER_OMEMMAX > 0 + while ((mem = TAKE_OMEM(inst)) != NULL) + { + alworker_release_omem(inst, mem, ALWORKER_DECMODE_ALLMEMORY); + } +#endif +} + +/*** name: handle_system_msg */ + +static int handle_system_msg(alworker_insthead_t *inst, + al_comm_msghdr_t hdr, + al_comm_msgopt_t *opt) +{ + unsigned char ret = AL_COMM_MSGCODEERR_UNKNOWN; + + switch (hdr.code) + { + case AL_COMM_MSGCODESYS_STOP: + if (!(IS_STATE_STOPPED(inst) || IS_STATE_STOPPING(inst))) + { + ret = AL_COMM_MSGCODEERR_OK; + if (g_cbs.on_stopmsg) + { + g_cbs.on_stopmsg(inst->state, inst); + } + + COMMFW_STATECHG_STOPPING(inst); + } + else + { + ret = AL_COMM_MSGCODEERR_INVALIDSTATE; + } + + break; + + case AL_COMM_MSGCODESYS_PLAY: + ret = AL_COMM_MSGCODEERR_INVALIDSTATE; + if (IS_STATE_STOPPED(inst) || + IS_STATE_STOPPING(inst) || + IS_STATE_PAUSING(inst) || + IS_STATE_PAUSED(inst)) + { + ret = AL_COMM_MSGCODEERR_OK; + if (g_cbs.on_playmsg) + { + ret = g_cbs.on_playmsg(inst->state, inst); + } + + if (ret == AL_COMM_MSGCODEERR_OK) + { + COMMFW_STATECHG_STARTING(inst); + } + } + + break; + + case AL_COMM_MSGCODESYS_TERM: + ret = AL_COMM_MSGCODEERR_OK; + if (g_cbs.on_termmsg) + { + g_cbs.on_termmsg(inst, hdr, opt); + } + + release_allmem(inst); + COMMFW_STATECHG_TERM(inst); + + break; + + case AL_COMM_MSGCODESYS_PARAM: + if (g_cbs.on_parammsg) + { + ret = g_cbs.on_parammsg(inst->state, inst, hdr, opt); + } + + break; + +#ifndef NOTUSE_SYSPAUSE + case AL_COMM_MSGCODESYS_PAUSE: + ret = AL_COMM_MSGCODEERR_INVALIDSTATE; + if (IS_STATE_PROCESS(inst)) + { + ret = AL_COMM_MSGCODEERR_OK; + if (g_cbs.on_pausemsg) + { + ret = g_cbs.on_pausemsg(inst->state, inst); + } + + if (ret == AL_COMM_MSGCODEERR_OK) + { + COMMFW_STATECHG_PAUSING(inst); + } + } + + break; +#endif + +#ifndef NOTUSE_SYSDBG + case AL_COMM_MSGCODESYS_DBG: + if (g_cbs.on_dbgmsg) + { + ret = g_cbs.on_dbgmsg(inst->state, inst, hdr, opt); + } + + break; +#endif + } + + return ret; +} + +/*** name: handle_outputmem_msg */ + +static int handle_outputmem_msg(alworker_insthead_t *inst, + al_comm_msghdr_t hdr, + al_comm_msgopt_t *opt) +{ +#if CONF_WORKER_OMEMMAX > 0 + unsigned char ret = AL_COMM_MSGCODEERR_OK; + memblk_t *memblk; + + if (hdr.code == AL_COMM_MSGCODEMEM_INJECT) + { + if (opt->addr && opt->size > 0) + { + memblk = TAKE_FREE_OMEM(inst); + if (memblk) + { + memblk_initout(memblk, (char *)opt->addr, opt->size); + memset(memblk->addr, 0, memblk->size); + PUSH_OMEM(memblk, inst); + + if (g_cbs.on_omeminject) + { + ret = g_cbs.on_omeminject(inst->state, inst); + } + + if (ret == AL_COMM_MSGCODEERR_OK) + { + if (IS_STATE_WAIT_OMEM(inst)) + { + COMMFW_STATECHG_PROCESS(inst); + } + else if (IS_STATE_WAIT_P_OMEM(inst)) + { + COMMFW_STATECHG_PAUSING(inst); + } + else if (IS_STATE_WAIT_S_OMEM(inst)) + { + COMMFW_STATECHG_STOPPING(inst); + } + } + + ret = AL_COMM_MSGCODEERR_OK; /* OK for no error return */ + } + else + { + ret = AL_COMM_MSGCODEERR_OVFLOW; + } + } + else + { + ret = AL_COMM_MSGCODEERR_INVALIDADDR; + } + } + else + { + ret = AL_COMM_MSGCODEERR_UNKNOWN; + } +#else + unsigned char ret = AL_COMM_MSGCODEERR_UNKNOWN; +#endif + + return ret; +} + +/*** name: handle_inputmem_msg */ + +static int handle_inputmem_msg(alworker_insthead_t *inst, + al_comm_msghdr_t hdr, + al_comm_msgopt_t *opt) +{ +#if CONF_WORKER_IMEMMAX > 0 + unsigned char ret = AL_COMM_MSGCODEERR_OK; + memblk_t *memblk; + + if (hdr.code == AL_COMM_MSGCODEMEM_INJECT) + { + if (opt->addr && opt->size > 0) + { + memblk = TAKE_FREE_IMEM(inst); + if (memblk) + { + ALWORKER_TRACE(); + memblk_initin(memblk, (char *)opt->addr, opt->size, opt->eof); + memblk->filled = opt->size; /* memory have been filled up */ + PUSH_IMEM(memblk, inst); + + if (g_cbs.on_imeminject) + { + ret = g_cbs.on_imeminject(inst->state, inst); + } + + if (ret == AL_COMM_MSGCODEERR_OK) + { + /* State change */ + + if (IS_STATE_WAIT_IMEM(inst)) + { + ALWORKER_TRACE(); + COMMFW_STATECHG_PROCESS(inst); + } + else if (IS_STATE_WAIT_P_IMEM(inst)) + { + ALWORKER_TRACE(); + COMMFW_STATECHG_PAUSING(inst); + } + else if (IS_STATE_WAIT_S_IMEM(inst)) + { + ALWORKER_TRACE(); + COMMFW_STATECHG_STOPPING(inst); + } + } + + ret = AL_COMM_MSGCODEERR_OK; /* OK for no error return */ + } + else + { + ret = AL_COMM_MSGCODEERR_OVFLOW; + } + } + else + { + ret = AL_COMM_MSGCODEERR_INVALIDADDR; + } + } + else + { + ret = AL_COMM_MSGCODEERR_UNKNOWN; + } +#else + unsigned char ret = AL_COMM_MSGCODEERR_UNKNOWN; +#endif + + return ret; +} + +/*** name: handle_instance_msg */ + +static int handle_instance_msg(alworker_insthead_t *inst, + al_comm_msghdr_t hdr, + al_comm_msgopt_t *opt) +{ + unsigned char ret = AL_COMM_MSGCODEERR_UNKNOWN; + + switch (hdr.code) + { +#ifndef NOTUSE_INSTGAIN + case AL_COMM_MSGCODEINST_GAIN: + if (g_cbs.on_gainmsg) + { + ret = g_cbs.on_gainmsg(inst->state, inst, opt->gain); + } + + break; +#endif + } + + return ret; +} + +/*** name: handle_message */ + +static void handle_message(alworker_insthead_t *inst, + al_comm_msghdr_t hdr, + al_comm_msgopt_t *opt) +{ + int ret = AL_COMM_MSGCODEERR_UNKNOWN; + + ALWORKER_DMSG("Receive G:%d C:%d\n", hdr.grp, hdr.code); + + switch (hdr.grp) + { + case AL_COMM_MESSAGE_SYS: + ret = handle_system_msg(inst, hdr, opt); + break; + + case AL_COMM_MESSAGE_FMEM: + ret = handle_inputmem_msg(inst, hdr, opt); + break; + + case AL_COMM_MESSAGE_OMEM: + ret = handle_outputmem_msg(inst, hdr, opt); + break; + + case AL_COMM_MESSAGE_INST: + ret = handle_instance_msg(inst, hdr, opt); + break; + + default: +#ifndef NOTUSE_ORGMSG + if (g_cbs.on_usrorgmsg) + { + ret = g_cbs.on_usrorgmsg(inst->state, inst, hdr, opt); + } +#else + ret = AL_COMM_MSGCODEERR_UNKNOWN; +#endif + break; + } + + if (hdr.type == AL_COMM_MSGTYPE_SYNC || ret != AL_COMM_MSGCODEERR_OK) + { + hdr.type = AL_COMM_MSGTYPE_RESP; + hdr.opt = ret; + al_send_message(&g_worker_task, hdr, opt); + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/*** name: alworker_commfw_get_cbtable */ + +alcommfw_cbs_t *alworker_commfw_get_cbtable(void) +{ + memset(&g_cbs, 0, sizeof(g_cbs)); + return &g_cbs; +} + +/*** name: alworker_commfw_initialize */ + +int alworker_commfw_initialize(alworker_insthead_t *head) +{ + int i; + +#if CONF_WORKER_IMEMMAX > 0 + sq_init(IN_FREEQ(head)); + sq_init(IN_AVAILQ(head)); + for (i = 0; i < CONF_WORKER_IMEMMAX; i++) + { + PUSH_FREE_IMEM(&head->imemblk[i], head); + } +#endif + +#if CONF_WORKER_OMEMMAX > 0 + sq_init(OUT_FREEQ(head)); + sq_init(OUT_AVAILQ(head)); + for (i = 0; i < CONF_WORKER_OMEMMAX; i++) + { + PUSH_FREE_OMEM(&head->omemblk[i], head); + } +#endif + + COMMFW_STATECHG_STOPPED(head); + return initialize_alworker(&g_worker_task, "", false); +} + +/*** name: alworker_commfw_pollmessage */ + +void alworker_commfw_pollmessage(alworker_insthead_t *inst) +{ + int block; + al_comm_msghdr_t hdr; + al_comm_msgopt_t opt; + + do + { + block = IS_BLOCKMSG(inst); + hdr = al_receive_message(&g_worker_task, &opt, block); + if (hdr.u32 != AL_COMM_NO_MSG) + { + handle_message(inst, hdr, &opt); + } + } + while (!block && hdr.u32 != AL_COMM_NO_MSG); +} + +void alworker_commfw_waitresp(alworker_insthead_t *inst, + al_comm_msghdr_t snd) +{ + al_comm_msghdr_t hdr; + al_comm_msgopt_t opt; + + while (1) + { + hdr = al_receive_message(&g_worker_task, &opt, 1); + if (hdr.u32 != AL_COMM_NO_MSG) + { + if (hdr.type == AL_COMM_MSGTYPE_RESP) + { + if (hdr.grp != snd.grp || hdr.code != snd.code) + { + printf("[Worker CommFW] Wrang Resp G(exp:%02x, act:%02x), " + "C(exp:%02x, act:%02x\n", + snd.grp, hdr.grp, snd.code, hdr.code); + } + + break; + } + + handle_message(inst, hdr, &opt); + } + } +} + +void alworker_commfw_msgloop(alworker_insthead_t *inst) +{ + int ret; + + while (IS_WORKER_RUNNING(inst)) + { + alworker_commfw_pollmessage(inst); + + switch (inst->state) + { + case COMMFW_STATE_STARTING: +#ifndef NOTUSE_STARTING + if (g_cbs.on_starting) + { + ret = g_cbs.on_starting((void *)inst); + if (ret == AL_COMM_MSGCODEERR_OK) + { + COMMFW_STATECHG_PROCESS(inst); + } + } + else +#endif + { + COMMFW_STATECHG_PROCESS(inst); + } + + break; + + case COMMFW_STATE_PROCESS: + if (g_cbs.on_process) + { + ret = g_cbs.on_process((void *)inst); + switch (ret) + { + case AL_COMMFW_RET_NOIMEM: + COMMFW_STATECHG_WAIT_IMEM(inst); + break; + + case AL_COMMFW_RET_NOOMEM: + COMMFW_STATECHG_WAIT_OMEM(inst); + break; + + case AL_COMMFW_RET_OK: + case AL_COMMFW_RET_STAY: + default: + + /* Do nothing */ + + break; + } + } + + break; /* end of case COMMFW_STATE_PROCESS */ + +#ifndef NOTUSE_SYSPAUSE + case COMMFW_STATE_PAUSING: + if (g_cbs.on_pausing) + { + ret = g_cbs.on_pausing((void *)inst); + switch (ret) + { + case AL_COMMFW_RET_NOIMEM: + COMMFW_STATECHG_WAIT_P_IMEM(inst); + break; + + case AL_COMMFW_RET_NOOMEM: + COMMFW_STATECHG_WAIT_P_OMEM(inst); + break; + + case AL_COMMFW_RET_OK: + COMMFW_STATECHG_PAUSED(inst); + break; + + case AL_COMMFW_RET_STAY: + default: + + /* Do nothing */ + + break; + } + } + else + { + /* No pausing handler means always ready to go to PAUSED state */ + + COMMFW_STATECHG_PAUSED(inst); + } + + break; /* end of case COMMFW_STATE_PAUSING */ +#endif + + case COMMFW_STATE_STOPPING: +#ifndef NOTUSE_STOPPING + if (g_cbs.on_stopping) + { + ret = g_cbs.on_stopping((void *)inst); + switch (ret) + { + case AL_COMMFW_RET_NOIMEM: + COMMFW_STATECHG_WAIT_S_IMEM(inst); + break; + + case AL_COMMFW_RET_NOOMEM: + COMMFW_STATECHG_WAIT_S_OMEM(inst); + break; + + case AL_COMMFW_RET_OK: + COMMFW_STATECHG_STOPPED(inst); + break; + + case AL_COMMFW_RET_STAY: + default: + + /* Do nothing */ + + break; + } + } + else +#endif + { + /* No stopping handler means always ready to go to STOPPED state */ + + COMMFW_STATECHG_STOPPED(inst); + } + + break; /* end of case COMMFW_STATE_STOPPING */ + + default: + break; + } /* end of switch (inst->state) */ + } /* while (IS_WORKER_RUNNING(inst)) */ +} + +/*** name: send_frameinfo */ + +int alworker_send_frameinfo(int id, int chs, int hz, int layer, int rate) +{ + al_comm_msghdr_t hdr; + al_comm_msgopt_t opt; + + hdr.grp = AL_COMM_MESSAGE_INST; + hdr.type = AL_COMM_MSGTYPE_ASYNC; + hdr.code = AL_COMM_MSGCODEINST_INFO; + hdr.opt = id; + + opt.dec_chs = chs; + opt.dec_hz = hz; + opt.dec_layer = layer; + opt.dec_kbps = rate; + + return al_send_message(&g_worker_task, hdr, &opt); +} + +/*** name: send_framedone */ + +int alworker_send_framedone(int id) +{ + al_comm_msghdr_t hdr; + al_comm_msgopt_t opt; + + hdr.grp = AL_COMM_MESSAGE_INST; + hdr.type = AL_COMM_MSGTYPE_ASYNC; + hdr.code = AL_COMM_MSGCODEINST_DONE; + hdr.opt = id; + + return al_send_message(&g_worker_task, hdr, &opt); +} + +/*** name: send_errormsg */ + +int alworker_send_errormsg(int id, int errcode) +{ + al_comm_msghdr_t hdr; + al_comm_msgopt_t opt; + + hdr.grp = AL_COMM_MESSAGE_SYS; + hdr.type = AL_COMM_MSGTYPE_ASYNC; + hdr.code = AL_COMM_MSGCODESYS_ERR; + hdr.opt = id; + + opt.errcode = errcode; + + return al_send_message(&g_worker_task, hdr, &opt); +} + +/*** name: send_bootmsg */ + +int alworker_send_bootmsg(int version, void *d) +{ + al_comm_msghdr_t hdr; + al_comm_msgopt_t opt; + + hdr.grp = AL_COMM_MESSAGE_SYS; + hdr.type = AL_COMM_MSGTYPE_ASYNC; + hdr.code = AL_COMM_MSGCODESYS_BOOT; + hdr.opt = version; + opt.addr = (unsigned char *)alworker_addr_convert(d); + + return al_send_message(&g_worker_task, hdr, &opt); +} + +int alworker_send_debug(alworker_insthead_t *inst, unsigned char hdr_opt) +{ + al_comm_msghdr_t hdr; + al_comm_msgopt_t opt; + + hdr.grp = AL_COMM_MESSAGE_SYS; + hdr.type = AL_COMM_MSGTYPE_SYNC; + hdr.code = AL_COMM_MSGCODESYS_DBG; + hdr.opt = hdr_opt; + + al_send_message(&g_worker_task, hdr, &opt); + alworker_commfw_waitresp(inst, hdr); + return OK; +} + +/*** name: release_framemem */ + +int alworker_release_imem(alworker_insthead_t *inst, int id, memblk_t *memblk) +{ + al_comm_msghdr_t hdr; + al_comm_msgopt_t opt; + + hdr.grp = AL_COMM_MESSAGE_FMEM; + hdr.type = AL_COMM_MSGTYPE_SYNC; + hdr.code = AL_COMM_MSGCODEMEM_RELEASE; + hdr.opt = (unsigned char)id; + + opt.addr = (unsigned char *)memblk->addr; + opt.size = memblk->size; + opt.eof = memblk->eof; + + al_send_message(&g_worker_task, hdr, &opt); + alworker_commfw_waitresp(inst, hdr); + return OK; +} + +/*** name: deliver_outpcm */ + +int alworker_release_omem(alworker_insthead_t *inst, memblk_t *memblk, int mode) +{ + al_comm_msghdr_t hdr; + al_comm_msgopt_t opt; + + hdr.grp = AL_COMM_MESSAGE_OMEM; + hdr.type = AL_COMM_MSGTYPE_SYNC; + hdr.code = AL_COMM_MSGCODEMEM_RELEASE; + hdr.opt = AL_COMM_MSGCODEERR_OK; + + opt.addr = (unsigned char *)memblk->addr; + opt.size = (mode == ALWORKER_DECMODE_JUSTDECODE) ? + memblk->filled : memblk->size; + opt.eof = memblk->eof; + + al_send_message(&g_worker_task, hdr, &opt); + alworker_commfw_waitresp(inst, hdr); + return OK; +} + +int alworker_free(memblk_t *mem, alworker_insthead_t *inst) +{ + int ret = -EINVAL; + + switch (mem->type) + { +#if CONF_WORKER_IMEMMAX > 0 + case MEMBLK_TYPE_INPUT: + ret = alworker_release_imem(inst, 0, mem); + PUSH_FREE_IMEM(mem, inst); + break; +#endif + +#if CONF_WORKER_OMEMMAX > 0 + case MEMBLK_TYPE_OUTPUT: + ret = alworker_release_omem(inst, mem, ALWORKER_DECMODE_JUSTDECODE); + PUSH_FREE_OMEM(mem, inst); + break; +#endif + } + + return ret; +} diff --git a/sdk/modules/audiolite/worker/common/alworker_commfw.h b/sdk/modules/audiolite/worker/common/alworker_commfw.h new file mode 100644 index 000000000..8a454a3a6 --- /dev/null +++ b/sdk/modules/audiolite/worker/common/alworker_commfw.h @@ -0,0 +1,345 @@ +/**************************************************************************** + * modules/audiolite/worker/common/alworker_commfw.h + * + * Copyright 2024 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __AUDIOLITE_WORKER_COMMON_ALWORKER_COMMFW_H +#define __AUDIOLITE_WORKER_COMMON_ALWORKER_COMMFW_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "audiolite/alworker_comm.h" +#include "alworker_commfw_config.h" +#include "alworker_memblk.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define ALWORKER_DECMODE_JUSTDECODE (0) +#define ALWORKER_DECMODE_ALLMEMORY (1) + +/* MACROs Related on Callback settings */ + +#define SET_STOPMSG(s, c) do { (s)->on_stopmsg = c; }while(0) +#define SET_PLAYMSG(s, c) do { (s)->on_playmsg = c; }while(0) +#define SET_TERMMSG(s, c) do { (s)->on_termmsg = c; }while(0) +#define SET_PROCESS(s, c) do { (s)->on_process = c; }while(0) +#define SET_PARAMMSG(s, c) do { (s)->on_parammsg = c; }while(0) + +#ifndef NOTUSE_STARTING +# define SET_STARTING(s, c) do { (s)->on_starting = c; }while(0) +#else +# define SET_STARTING(s, c) +#endif + +#ifndef NOTUSE_STOPPING +# define SET_STOPPING(s, c) do { (s)->on_stopping = c; }while(0) +#else +# define SET_STOPPING(s, c) +#endif + +#ifndef NOTUSE_SYSPAUSE +# define SET_PAUSEMSG(s, c) do { (s)->on_pausemsg = c; }while(0) +# define SET_PAUSING(s, c) do { (s)->on_pausing = c; }while(0) +#else +# define SET_PAUSEMSG(s, c) +# define SET_PAUSING(s, c) +#endif + +#ifndef NOTUSE_SYSDBG +# define SET_DBGMSG(s, c) do { (s)->on_dbgmsg = c; }while(0) +#else +# define SET_DBGMSG(s, c) +#endif + +#ifndef NOTUSE_ORGMSG +# define SET_USRMSG(s, c) do { (s)->on_usrorgmsg = c; }while(0) +#else +# define SET_USRMSG(s, c) +#endif + +#ifndef NOTUSE_INSTGAIN +# define SET_GAINMSG(s, c) do { (s)->on_gainmsg = c; }while(0) +#else +# define SET_GAINMSG(s, c) +#endif + +/* MACROs Related on Framework Instance and memblk queue */ + +#define FREE_MEMBLK(m, i) alworker_free(m, (alworker_insthead_t *)i) + +#if CONF_WORKER_IMEMMAX > 0 +# define INPUT_MEM_INSTANCE \ + sq_queue_t ifreeq; \ + sq_queue_t iavailq; \ + memblk_t imemblk[CONF_WORKER_IMEMMAX]; +# define SET_IMEMINJECT(s, c) do { (s)->on_imeminject = c; }while(0) +# define IN_FREEQ(instobj) (&(instobj)->ifreeq) +# define IN_AVAILQ(instobj) (&(instobj)->iavailq) +# define TAKE_FREE_IMEM(instobj) \ + ((memblk_t *)sq_remfirst(IN_FREEQ(instobj))) +# define PUSH_FREE_IMEM(e, instobj) \ + sq_addlast((sq_entry_t *)e, IN_FREEQ(instobj)) +# define PEEK_IMEM(instobj) ((memblk_t *)sq_peek(IN_AVAILQ(instobj))) +# define TAKE_IMEM(instobj) ((memblk_t *)sq_remfirst(IN_AVAILQ(instobj))) +# define PUSH_IMEM(e, instobj) sq_addlast((sq_entry_t *)e, IN_AVAILQ(instobj)) +# define IMEM_NUM(instobj) sq_count(IN_AVAILQ(instobj)) +#else +# define INPUT_MEM_INSTANCE +# define SET_IMEMINJECT(s, c) +# define IN_FREEQ(instobj) (NULL) +# define IN_AVAILQ(instobj) (NULL) +# define TAKE_FREE_IMEM(instobj) ((memblk_t *)NULL) +# define PUSH_FREE_IMEM(e, instobj) +# define PEEK_IMEM(instobj) ((memblk_t *)NULL) +# define TAKE_IMEM(instobj) ((memblk_t *)NULL) +# define PUSH_IMEM(e, instobj) +# define IMEM_NUM(instobj) (0) +#endif + +#if CONF_WORKER_OMEMMAX > 0 +# define OUTPUT_MEM_INSTANCE \ + sq_queue_t ofreeq; \ + sq_queue_t oavailq; \ + memblk_t omemblk[CONF_WORKER_OMEMMAX]; +# define SET_OMEMINJECT(s, c) do { (s)->on_omeminject = c; }while(0) +# define OUT_FREEQ(instobj) (&(instobj)->ofreeq) +# define OUT_AVAILQ(instobj) (&(instobj)->oavailq) +# define TAKE_FREE_OMEM(instobj) \ + ((memblk_t *)sq_remfirst(OUT_FREEQ(instobj))) +# define PUSH_FREE_OMEM(e, instobj) \ + sq_addlast((sq_entry_t *)e, OUT_FREEQ(instobj)) +# define PEEK_OMEM(instobj) ((memblk_t *)sq_peek(OUT_AVAILQ(instobj))) +# define TAKE_OMEM(instobj) ((memblk_t *)sq_remfirst(OUT_AVAILQ(instobj))) +# define PUSH_OMEM(e, instobj) sq_addlast((sq_entry_t *)e, OUT_AVAILQ(instobj)) +# define OMEM_NUM(instobj) sq_count(OUT_AVAILQ(instobj)) +#else +# define OUTPUT_MEM_INSTANCE +# define SET_OMEMINJECT(s, c) +# define OUT_FREEQ(instobj) (NULL) +# define OUT_AVAILQ(instobj) (NULL) +# define TAKE_FREE_OMEM(instobj) ((memblk_t *)NULL) +# define PUSH_FREE_OMEM(e, instobj) +# define PEEK_OMEM(instobj) ((memblk_t *)NULL) +# define TAKE_OMEM(instobj) ((memblk_t *)NULL) +# define PUSH_OMEM(e, instobj) +# define OMEM_NUM(instobj) (0) +#endif + +#define ALWORKERCOMMFW_INSTANCE \ + struct { \ + unsigned char state; \ + INPUT_MEM_INSTANCE \ + OUTPUT_MEM_INSTANCE \ + }; + +/* MACROs Related on State */ + +#define COMMFW_BLOCK_WAITMSG (0x80) + +#define COMMFW_STATE_STOPPED (0 | COMMFW_BLOCK_WAITMSG) +#define COMMFW_STATE_STARTING (1) +#define COMMFW_STATE_PROCESS (2) +#define COMMFW_STATE_WAIT_IMEM (3 | COMMFW_BLOCK_WAITMSG) +#define COMMFW_STATE_WAIT_OMEM (4 | COMMFW_BLOCK_WAITMSG) +#define COMMFW_STATE_PAUSING (5) +#define COMMFW_STATE_WAIT_P_IMEM (6 | COMMFW_BLOCK_WAITMSG) +#define COMMFW_STATE_WAIT_P_OMEM (7 | COMMFW_BLOCK_WAITMSG) +#define COMMFW_STATE_PAUSED (8 | COMMFW_BLOCK_WAITMSG) +#define COMMFW_STATE_STOPPING (9) +#define COMMFW_STATE_WAIT_S_IMEM (10 | COMMFW_BLOCK_WAITMSG) +#define COMMFW_STATE_WAIT_S_OMEM (11 | COMMFW_BLOCK_WAITMSG) +#define COMMFW_STATE_TERM (12) + +#define IS_BLOCKMSG(i) ((i)->state & COMMFW_BLOCK_WAITMSG) +#define IS_WORKER_RUNNING(i) ((i)->state != COMMFW_STATE_TERM) + +#ifdef ALWORKER_COMMFW_DEBUG_STATE +# define COMMFW_STATECHG(i,s) do { \ + printf("[WORKER} State %d -> %d\n", (i)->state, COMMFW_STATE_##s); \ + ((i)->state = COMMFW_STATE_##s); \ + }while(0) +#else +# define COMMFW_STATECHG(i,s) ((i)->state = COMMFW_STATE_##s) +#endif + +#define COMMFW_STATECHG_STOPPED(i) COMMFW_STATECHG(i, STOPPED) +#define COMMFW_STATECHG_STARTING(i) COMMFW_STATECHG(i, STARTING) +#define COMMFW_STATECHG_PROCESS(i) COMMFW_STATECHG(i, PROCESS) +#define COMMFW_STATECHG_WAIT_IMEM(i) COMMFW_STATECHG(i, WAIT_IMEM) +#define COMMFW_STATECHG_WAIT_OMEM(i) COMMFW_STATECHG(i, WAIT_OMEM) +#define COMMFW_STATECHG_PAUSING(i) COMMFW_STATECHG(i, PAUSING) +#define COMMFW_STATECHG_WAIT_P_IMEM(i) COMMFW_STATECHG(i, WAIT_P_IMEM) +#define COMMFW_STATECHG_WAIT_P_OMEM(i) COMMFW_STATECHG(i, WAIT_P_OMEM) +#define COMMFW_STATECHG_PAUSED(i) COMMFW_STATECHG(i, PAUSED) +#define COMMFW_STATECHG_STOPPING(i) COMMFW_STATECHG(i, STOPPING) +#define COMMFW_STATECHG_WAIT_S_IMEM(i) COMMFW_STATECHG(i, WAIT_S_IMEM) +#define COMMFW_STATECHG_WAIT_S_OMEM(i) COMMFW_STATECHG(i, WAIT_S_OMEM) +#define COMMFW_STATECHG_TERM(i) COMMFW_STATECHG(i, TERM) + +#define COMMFW_IS_STATE(i, s) ((i)->state == COMMFW_STATE_##s) + +#define IS_STATE_STOPPED(i) COMMFW_IS_STATE(i, STOPPED) +#define IS_STATE_STARTING(i) COMMFW_IS_STATE(i, STARTING) +#define IS_STATE_PROCESS(i) COMMFW_IS_STATE(i, PROCESS) +#define IS_STATE_WAIT_IMEM(i) COMMFW_IS_STATE(i, WAIT_IMEM) +#define IS_STATE_WAIT_OMEM(i) COMMFW_IS_STATE(i, WAIT_OMEM) +#define IS_STATE_PAUSING(i) COMMFW_IS_STATE(i, PAUSING) +#define IS_STATE_WAIT_P_IMEM(i) COMMFW_IS_STATE(i, WAIT_P_IMEM) +#define IS_STATE_WAIT_P_OMEM(i) COMMFW_IS_STATE(i, WAIT_P_OMEM) +#define IS_STATE_PAUSED(i) COMMFW_IS_STATE(i, PAUSED) +#define IS_STATE_STOPPING(i) COMMFW_IS_STATE(i, STOPPING) +#define IS_STATE_WAIT_S_IMEM(i) COMMFW_IS_STATE(i, WAIT_S_IMEM) +#define IS_STATE_WAIT_S_OMEM(i) COMMFW_IS_STATE(i, WAIT_S_OMEM) + +/* Return code of process state */ + +#define AL_COMMFW_RET_OK (0) +#define AL_COMMFW_RET_NOIMEM (1) +#define AL_COMMFW_RET_NOOMEM (2) +#define AL_COMMFW_RET_STAY (3) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct alworker_commfw_insthead_s +{ + unsigned char state; + INPUT_MEM_INSTANCE + OUTPUT_MEM_INSTANCE +}; +typedef struct alworker_commfw_insthead_s alworker_insthead_t; + +struct alworker_commfw_callbacks_s +{ + void (*on_stopmsg)(int state, void *arg); + int (*on_playmsg)(int state, void *arg); + void (*on_termmsg)(void *arg, + al_comm_msghdr_t hdr, al_comm_msgopt_t *opt); + int (*on_process)(void *arg); + int (*on_parammsg)(int state, void *arg, + al_comm_msghdr_t hdr, al_comm_msgopt_t *opt); +#if CONF_WORKER_IMEMMAX > 0 + int (*on_imeminject)(int state, void *arg); +#endif +#if CONF_WORKER_OMEMMAX > 0 + int (*on_omeminject)(int state, void *arg); +#endif +#ifndef NOTUSE_STARTING + int (*on_starting)(void *arg); +#endif +#ifndef NOTUSE_STOPPING + int (*on_stopping)(void *arg); +#endif +#ifndef NOTUSE_SYSPAUSE + int (*on_pausemsg)(int state, void *arg); + int (*on_pausing)(void *arg); +#endif +#ifndef NOTUSE_SYSDBG + int (*on_dbgmsg)(int state, void *arg, + al_comm_msghdr_t hdr, al_comm_msgopt_t *opt); +#endif +#ifndef NOTUSE_ORGMSG + int (*on_usrorgmsg)(int state, void *arg, + al_comm_msghdr_t hdr, al_comm_msgopt_t *opt); +#endif +#ifndef NOTUSE_INSTGAIN + int (*on_gainmsg)(int state, void *arg, float gain); +#endif +}; +typedef struct alworker_commfw_callbacks_s alcommfw_cbs_t; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* alworker_commfw_initialize() + * Innitiaizing worker side instance of asmp. + * + * @Return Code: Always AL_COMM_ERR_SUCCESS + */ + +int alworker_commfw_initialize(alworker_insthead_t *inst); + +/* alworker_commfw_get_cbtable() + * Get callback table. + */ + +alcommfw_cbs_t *alworker_commfw_get_cbtable(void); + +/* alworker_commfw_pollmessage() + * Handle messages from main-core. + * + * @param [in] block : Set 1 to block this function returned until + * comming next message from main-core. + * 0 means just check if a message is came or not. + * @param [in] arg : + * to contain a input memory. + */ + +void alworker_commfw_pollmessage(alworker_insthead_t *arg); + +void alworker_commfw_waitresp(alworker_insthead_t *inst, + al_comm_msghdr_t snd); + +/* alworker_commfw_msgloop() + * Message loop for this framework. + * When this is called, start waiting message from HOST. + * And call registered callbacks depending on the state and a message. + * In this loop, state transition is also done. + * + * @param [in] arg : Instance of this framework. + */ + +void alworker_commfw_msgloop(alworker_insthead_t *arg); + +/* Send messages from worker */ + +int alworker_send_frameinfo(int id, int chs, int hz, int layer, int rate); +int alworker_send_framedone(int id); +int alworker_send_errormsg(int id, int errcode); +int alworker_send_bootmsg(int version, void *d); +int alworker_send_debug(alworker_insthead_t *inst, unsigned char hdr_opt); +int alworker_release_imem(alworker_insthead_t *inst, int id, memblk_t *memblk); +int alworker_release_omem(alworker_insthead_t *inst, memblk_t *memblk, int mode); +int alworker_free(memblk_t *mem, alworker_insthead_t *inst); + +#endif /* __AUDIOLITE_WORKER_COMMON_ALWORKER_COMMFW_H */ diff --git a/sdk/modules/audiolite/worker/common/alworker_memblk.c b/sdk/modules/audiolite/worker/common/alworker_memblk.c new file mode 100644 index 000000000..2a44e5911 --- /dev/null +++ b/sdk/modules/audiolite/worker/common/alworker_memblk.c @@ -0,0 +1,471 @@ +/**************************************************************************** + * modules/audiolite/worker/common/alworker_memblk.c + * + * Copyright 2024 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include "alworker_memblk.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef MIN +# define MIN(a,b) ((a) > (b) ? (b) : (a)) +#endif + +#define TEMPLATE_PUSH_POP(name, type) \ + type memblk_pop_##name(memblk_t *mb) \ + { \ + type ret = *((type *)memblk_dataptr(mb)); \ + memblk_updateused(mb, sizeof(type)); \ + return ret; \ + } \ + void memblk_push_##name(memblk_t *mb, type val) \ + { \ + memblk_fillupraw(mb, (char *)&val, sizeof(type)); \ + } + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/* memblk_shift + * + * Shift remain data to top of the memory + * + * [After] + * +--------------------------+ + * |12341234 | + * +--------------------------+ + * ^ ^ ^ + * used filled | + * | + * [Before] | + * +--------------------------+ + * | 12341234 | + * +--------------------------+ + * ^ ^ + * used filled + */ + +void memblk_shift(memblk_t *mb) +{ + int remain = memblk_remain(mb); + + if (remain && mb->used != 0) + { + memmove(mb->addr, &mb->addr[mb->used], remain); + } + + memblk_setfilled(mb, remain); + memblk_setused(mb, 0); +} + +/* memblk_shift_drop + * + * Drop data and Shift remain data to top of the memory + * + * [After] + * +--------------------------+ + * |34 | + * +--------------------------+ + * ^ ^filled ^ + * used | + * | + * [Before] <-sz-> | + * +--------------------------+ + * | 12341234 | + * +--------------------------+ + * ^ ^ + * used filled + */ + +void memblk_shift_drop(memblk_t *mb, int sz) +{ + int remain = memblk_remain(mb); + remain = remain - MIN(remain, sz); + + if (remain && (mb->used + sz) != 0) + { + memmove(mb->addr, &mb->addr[mb->used + sz], remain); + } + + memblk_setfilled(mb, remain); + memblk_setused(mb, 0); +} + +/* memblk_fillup + * + * Copy remaining data in src to the space of dst. + */ + +int memblk_fillup(memblk_t *dst, memblk_t *src) +{ + int cpysize = MIN(memblk_space(dst), memblk_remain(src)); + + memcpy(memblk_fillptr(dst), memblk_dataptr(src), cpysize); + memblk_updatefilled(dst, cpysize); + memblk_updateused(src, cpysize); + + return cpysize; +} + +/* memblk_fillup + * + * Copy data stored in src to the space of dst. + */ + +int memblk_fillupraw(memblk_t *dst, char *src, int sz) +{ + int cpysize = MIN(memblk_space(dst), sz); + + memcpy(memblk_fillptr(dst), src, cpysize); + memblk_updatefilled(dst, cpysize); + + return cpysize; +} + +/* memblk_single16 + * + * Reduce channel from embedded LR dual channels. + * + * Dstination(Lch only) + * +------------+ + * |131313131313| + * +------------+ + * ^ + * | + * +--------------------------+ + * |12341234123412341234123412| + * +--------------------------+ + * Dual channel + */ + +int memblk_single16(memblk_t *lch, memblk_t *src) +{ + int i; + int samples; + short *lchadr = (short *)memblk_fillptr(lch); + short *srcadr = (short *)memblk_dataptr(src); + + samples = MIN(memblk_space(lch), memblk_remain(src)/2); + samples /= sizeof(short); + + for (i = 0; i < samples; i++) + { + *lchadr++ = *srcadr++; + srcadr++; + } + + samples *= sizeof(short); + + memblk_updatefilled(lch, samples); + memblk_updateused(src, samples * 2); + + return samples; +} + +/* memblk_duplicate16 + * + * Duplicate embedded single channel data into distination. + * + * Dstination + * +--------------------------+ + * |11221122112211221122112211| + * +--------------------------+ + * ^ + * | + * +------------+ + * |121212121212| + * +------------+ + * Source Plane + */ + +int memblk_duplicate16(memblk_t *dst, memblk_t *src) +{ + int i; + int samples; + short *srcadr = (short *)memblk_dataptr(src); + short *dstadr = (short *)memblk_fillptr(dst); + + samples = MIN(memblk_remain(src), memblk_space(dst) / 2); + samples /= sizeof(short); + + for (i = 0; i < samples; i++) + { + *dstadr++ = *srcadr; + *dstadr++ = *srcadr++; + } + + samples *= sizeof(short); + + src->used += samples; + dst->filled += samples * 2; + + return samples * 2; +} + +/* memblk_split_lr16 + * + * Split embedded LR data into Lch and Rch plane. + * + * Lch Plane Rch Plane + * +------------+ +------------+ + * |LLLLLLLLLLLL| |RRRRRRRRRRRR| + * +------------+ +------------+ + * ^ ^ + * | | + * +--------------------------+ + * |LRLRLRLRLRLRLRLRLRLRLRLRLR| + * +--------------------------+ + * Source data + */ + +int memblk_split_lr16(memblk_t *lch, memblk_t *rch, memblk_t *src) +{ + int i; + int split_samples; + short *lchadr = (short *)memblk_fillptr(lch); + short *rchadr = (short *)memblk_fillptr(rch); + short *srcadr = (short *)memblk_dataptr(src); + + ALWORKER_DBGASSERT(memblk_space(rch) == memblk_space(lch)); + + split_samples = MIN(memblk_remain(src) / 2, memblk_space(lch)); + split_samples /= sizeof(short); + + for (i = 0; i < split_samples; i++) + { + *lchadr++ = *srcadr++; + *rchadr++ = *srcadr++; + } + + split_samples *= sizeof(short); + + memblk_updatefilled(lch, split_samples); + memblk_updatefilled(rch, split_samples); + memblk_updateused(src, split_samples * 2); + + return split_samples; +} + +/* memblk_conbine_lr16 + * + * Conbine Lch and Rch plane data to LR embedded in dst. + * + * Dstination + * +--------------------------+ + * |LRLRLRLRLRLRLRLRLRLRLRLRLR| + * +--------------------------+ + * ^ ^ + * | | + * +------------+ +------------+ + * |LLLLLLLLLLLL| |RRRRRRRRRRRR| + * +------------+ +------------+ + * Lch Plane Rch Plane + */ + +int memblk_conbine_lr16(memblk_t *dst, memblk_t *lch, memblk_t *rch) +{ + int i; + int samples; + short *dstadr = (short *)memblk_fillptr(dst); + short *lchadr = (short *)memblk_dataptr(lch); + short *rchadr = (short *)memblk_dataptr(rch); + + samples = MIN(memblk_remain(lch), memblk_remain(rch)); + samples = MIN(memblk_space(dst) / 2, samples); + + samples = samples / sizeof(short); + + for (i = 0; i < samples; i++) + { + dstadr[i * 2 + 1] = *rchadr++; /* Odd is copied first */ + dstadr[i * 2 + 0] = *lchadr++; + } + + samples *= sizeof(short); + + memblk_updatefilled(dst, samples * 2); + memblk_updateused(lch, samples); + memblk_updateused(rch, samples); + + return samples * 2; +} + +/* memblk_conbine_lr16acc + * + * Conbine Lch and Rch plane data to LR embedded. + * To reduce using memory, distination memory, lch memory + * and rch memory are shared. + * + * <---- Distination ------> Half of Lch(or Rch) + * +------------+------------+ +----+ + * | Lch plane | Rch plane | |Acc | + * +------------+------------+ +----+ + */ + +int memblk_conbine_lr16acc(memblk_t *dst, memblk_t *lch, + memblk_t *rch, memblk_t *acc) +{ + memblk_t tmp_rch; + + ALWORKER_DBGASSERT(lch->addr == dst->addr); + ALWORKER_DBGASSERT(&lch->addr[lch->size] == rch->addr); + ALWORKER_DBGASSERT(lch->size == rch->size); + ALWORKER_DBGASSERT(dst->size == lch->size * 2); + + /* Make sure Lch and Rch data is started from the top */ + + memblk_shift(lch); + memblk_shift(rch); + + /* Make the destination instance empty */ + + memblk_reset(dst); + + /* Swap data between lch bottom half and rch top half */ + + memcpy(acc->addr, &lch->addr[lch->size / 2], lch->size / 2); + memcpy(&lch->addr[lch->size / 2], rch->addr, lch->size / 2); + memcpy(rch->addr, acc->addr, lch->size / 2); + + /* Copy top half of lch to accumulater for making space on top of lch mem */ + + memblk_reset(acc); + memcpy(acc->addr, lch->addr, lch->size / 2); + memblk_init(&tmp_rch, &lch->addr[lch->size / 2], lch->size / 2); + acc->filled = lch->size / 2; + tmp_rch.filled = lch->size / 2; + + /* Conbine Lch and Rch half data */ + + memblk_conbine_lr16(dst, acc, &tmp_rch); + + /* Copy top half of lch to accumlater for making space on top of rch mem */ + + memblk_reset(acc); + memcpy(acc->addr, rch->addr, rch->size / 2); + memblk_init(&tmp_rch, &rch->addr[rch->size / 2], rch->size / 2); + acc->filled = lch->size / 2; + tmp_rch.filled = lch->size / 2; + + /* Conbine Lch and Rch half data */ + + memblk_conbine_lr16(dst, acc, &tmp_rch); + + /* Data size in destination is total of lch and rch */ + + dst->filled = memblk_remain(lch) + memblk_remain(rch); + + memblk_reset(lch); /* Make the instance empty */ + memblk_reset(rch); /* Make the instance empty */ + + return memblk_remain(dst); +} + +int memblk_conv_pcm16tofloat(memblk_t *flt, memblk_t *pcm16) +{ + int i; + int fltspace = memblk_space(flt) / sizeof(float); + int samp_num = memblk_remain(pcm16) / sizeof(short); + float *fdat = (float *)memblk_fillptr(flt); + short *pcm = (short *)memblk_dataptr(pcm16); + + samp_num = (samp_num > fltspace) ? fltspace : samp_num; + + for (i = 0; i < samp_num; i++) + { + *fdat++ = (float)*pcm++; + } + + memblk_updatefilled(flt, sizeof(float) * samp_num); + memblk_updateused(pcm16, sizeof(short) * samp_num); + + return samp_num; +} + +int memblk_conv_flattopcm16(memblk_t *pcm16, memblk_t *flt, float gain) +{ + int i; + int fltspace = memblk_remain(flt) / sizeof(float); + int samp_num = memblk_space(pcm16) / sizeof(short); + float *fdat = (float *)memblk_dataptr(flt); + short *pcm = (short *)memblk_fillptr(pcm16); + + samp_num = (samp_num > fltspace) ? fltspace : samp_num; + + for (i = 0; i < samp_num; i++) + { + /* TODO: Use CMSIS for the gain */ + + *pcm++ = gain * (short)*fdat++; + } + + memblk_updateused(flt, sizeof(float) * samp_num); + memblk_updatefilled(pcm16, sizeof(short) * samp_num); + + return samp_num; +} + +int memblk_normalizef(memblk_t *flt, float min, float max) +{ + int i; + int remain = memblk_remain(flt) / sizeof(float); + float *dat = (float *)memblk_dataptr(flt); + float div = max - min; + + if (div <= 0.f) + { + return -1; + } + + for (i = 0; i < remain; i++, dat++) + { + *dat = (*dat - min) / div; + if (*dat < -1) *dat = -1; + else if (*dat > 1) *dat = 1; + } + + return remain; +} + +TEMPLATE_PUSH_POP(float, float) +TEMPLATE_PUSH_POP(uint8, uint8_t) +TEMPLATE_PUSH_POP(int16, int16_t) diff --git a/sdk/modules/audiolite/worker/common/alworker_memblk.h b/sdk/modules/audiolite/worker/common/alworker_memblk.h new file mode 100644 index 000000000..d557b38e4 --- /dev/null +++ b/sdk/modules/audiolite/worker/common/alworker_memblk.h @@ -0,0 +1,153 @@ +/**************************************************************************** + * modules/audiolite/worker/common/alworker_memblk.h + * + * Copyright 2024 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __AUDIOLITE_WORKER_COMMON_ALWORKER_MEMBLK_H +#define __AUDIOLITE_WORKER_COMMON_ALWORKER_MEMBLK_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#ifdef ALWORKER_ENABLE_ASSERTION +#include +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef ALWORKER_ENABLE_ASSERTION +# define ALWORKER_DBGASSERT(cond) \ + do { \ + if (!(cond)) { \ + printf("!! ASSERT @ %s(%d): Condition [" #cond "] is failed\n", \ + __FILE__, __LINE__); \ + while (1); \ + } \ + } while(0) +#else +# define ALWORKER_DBGASSERT(cond) +#endif + +#define MEMBLK_TYPE_INPUT (0) +#define MEMBLK_TYPE_OUTPUT (1) +#define MEMBLK_TYPE_LOCAL (2) + +#define memblk_initialize(mb, ad, sz, e, t) \ + do { \ + (mb)->addr = (ad); \ + (mb)->size = (sz); \ + (mb)->eof = (e); \ + (mb)->filled = 0; \ + (mb)->used = 0; \ + (mb)->type = (t); \ + } while (0) + +#define memblk_init(mb, ad, sz) \ + memblk_initialize(mb, ad, sz, 0, MEMBLK_TYPE_LOCAL) + +#define memblk_initin(mb, ad, sz, e) \ + memblk_initialize(mb, ad, sz, e, MEMBLK_TYPE_INPUT) + +#define memblk_initout(mb, ad, sz) \ + memblk_initialize(mb, ad, sz, 0, MEMBLK_TYPE_OUTPUT) + +#define memblk_setfilled(mb, sz) ((mb)->filled = (sz)) +#define memblk_setused(mb, sz) ((mb)->used = (sz)) +#define memblk_updatefilled(mb, sz) ((mb)->filled += (sz)) +#define memblk_updateused(mb, sz) ((mb)->used += (sz)) +#define memblk_remain(mb) ((mb)->filled - (mb)->used) +#define memblk_space(mb) ((mb)->size - (mb)->filled) +#define memblk_is_empty(mb) ((mb)->used == (mb)->filled) +#define memblk_is_full(mb) ((mb)->filled == (mb)->size) +#define memblk_is_eof(mb) ((mb)->eof != 0) +#define memblk_is_input(mb) ((mb)->type == MEMBLK_TYPE_INPUT) +#define memblk_is_output(mb) ((mb)->type == MEMBLK_TYPE_OUTPUT) +#define memblk_is_local(mb) ((mb)->type == MEMBLK_TYPE_LOCAL) +#define memblk_set_eof(mb) ((mb)->eof = 1) +#define memblk_reset_eof(mb) ((mb)->eof = 0) +#define memblk_reset(mb) ((mb)->used = (mb)->filled = 0) +#define memblk_fillptr(mb) (&(mb)->addr[(mb)->filled]) +#define memblk_dataptr(mb) (&(mb)->addr[(mb)->used]) +#define memblk_nextblk(mb) ((memblk_t *)(mb)->link.flink) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct memblk_s +{ + sq_entry_t link; + char *addr; + int size; + int filled; + int used; + int eof; + int type; +}; +typedef struct memblk_s memblk_t; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +void memblk_shift(memblk_t *mb); +void memblk_shift_drop(memblk_t *mb, int sz); +int memblk_fillup(memblk_t *dst, memblk_t *src); +int memblk_splitch(memblk_t *lch, memblk_t *rch, memblk_t *itrleave, + memblk_t *acc); +int memblk_fillupraw(memblk_t *dst, char *src, int sz); + +int memblk_single16(memblk_t *lch, memblk_t *src); +int memblk_duplicate16(memblk_t *dst, memblk_t *src); +int memblk_split_lr16(memblk_t *lch, memblk_t *rch, memblk_t *src); +int memblk_conbine_lr16(memblk_t *dst, memblk_t *lch, memblk_t *rch); +int memblk_conbine_lr16acc(memblk_t *dst, memblk_t *lch, + memblk_t *rch, memblk_t *acc); +int memblk_conv_pcm16tofloat(memblk_t *flt, memblk_t *pcm16); +int memblk_conv_floattopcm16(memblk_t *pcm16, memblk_t *flt); +int memblk_normalizef(memblk_t *flt, float min, float max); + +float memblk_pop_float(memblk_t *mb); +void memblk_push_float(memblk_t *mb, float val); +short memblk_pop_int16(memblk_t *mb); +void memblk_push_int16(memblk_t *mb, int16_t val); +uint8_t memblk_pop_uint8(memblk_t *mb); +void memblk_push_uint8(memblk_t *mb, uint8_t val); + +#endif /* __AUDIOLITE_WORKER_COMMON_ALWORKER_MEMBLK_H */ diff --git a/sdk/modules/audiolite/worker/common/mkfiles/alworker.mk b/sdk/modules/audiolite/worker/common/mkfiles/alworker.mk new file mode 100644 index 000000000..d6f5ce6b8 --- /dev/null +++ b/sdk/modules/audiolite/worker/common/mkfiles/alworker.mk @@ -0,0 +1,116 @@ +ifeq ($(BUILD_EXECUTE),1) + +all: depend $(SPK) + +# For alworker common dir +ALWORKER_COMMONMKS = $(ALWORKER_COMMON)/mkfiles + +CSRCS += alworker_comm.c +CSRCS += alworker_commfw.c +CSRCS += alworker_memblk.c + +# For SPK tools + +MKSPK_TOOLDIR = $(TOPDIR)/tools/cxd56 +MKSPK_MKFILE = $(MKSPK_TOOLDIR)/Makefile.host +MKSPK_TOOL = $(MKSPK_TOOLDIR)/mkspk +MKSPK_TOOL_OPT = -c 2 + +# Setup to build and linking worker support library + +WORKER_DIR = $(SDKDIR)$(DELIM)modules$(DELIM)asmp$(DELIM)worker +WORKER_LIB = $(WORKER_DIR)$(DELIM)libasmpw$(LIBEXT) +LDLIBPATH += -L $(WORKER_DIR) +LDLIBS += -lasmpw + +ifneq ($(CONFIG_ASMP_WORKER_CMSIS),) +include $(ALWORKER_COMMONMKS)/cmsis.mk +endif + +ifeq ($(ALWORKER_USE_RESAMPLER),1) +include $(ALWORKER_COMMONMKS)/resampler.mk +endif + +AUDIOLITE_DIR = $(ALWORKER_COMMON)/../.. + +CFLAGS += -DBUILD_TGT_ASMPWORKER + +VPATH = $(ALWORKER_COMMON) $(VPATH_DIRS) + +DELTGT_FILES = $(CSRCS:.c=.o) + +INCDIRS += . $(ALWORKER_COMMON) $(AUDIOLITE_DIR)/../include + +CFLAGS += -O3 +ifeq ($(WINTOOL),y) +CFLAGS += -I"$(shell cygpath -w $(SDKDIR)/modules/asmp/worker)" +CFLAGS += $(foreach d,$(INCDIRS), -I"$(shell cygpath -w $(d))") +else +CFLAGS += -I$(SDKDIR)/modules/asmp/worker +CFLAGS += $(foreach d,$(INCDIRS), -I$(d)) +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +LIBGCC = "$(shell "$(CC)" $(ARCHCPUFLAGS) -print-libgcc-file-name)" + +$(COBJS): %$(OBJEXT): %.c + @echo "CC: $<" + $(Q) $(CC) -c $(CFLAGS) $< -o $@ + +$(AOBJS): %$(OBJEXT): %.S + @echo "AS: $<" + $(Q) $(CC) -c $(AFLAGS) $< -o $@ + +$(BIN): $(COBJS) $(AOBJS) | $(WORKER_LIB) $(CMSIS_DSP_LIB) + @echo "LD: $@" + $(Q) $(LD) $(LDRAWELFFLAGS) -e main --gc-sections $(LDLIBPATH) -o $@ \ + --start-group $(ARCHCRT0OBJ) $^ $(LDLIBS) $(LIBGCC) --end-group + $(Q) cp $(BIN) $(BIN).debug.elf + $(Q) $(STRIP) -d $(BIN) + +$(MKSPK_TOOL): + @$(MAKE) -C $(MKSPK_TOOLDIR) -f $(MKSPK_MKFILE) TOPDIR="$(TOPDIR)" + +$(SPK): $(MKSPK_TOOL) $(BIN) + @echo "MKSPK: $@" + $(MKSPK_TOOL) $(MKSPK_TOOL_OPT) $(BIN) $(BIN) $(SPK) + mkdir -p $(SDKDIR)/workerspks + cp $(SPK) $(SDKDIR)/workerspks + +clean: + $(call DELFILE, $(BIN)) + $(call DELFILE, $(BIN).debug.elf) + $(call DELFILE, $(DELTGT_FILES)) + $(call DELFILE, $(SPK)) + $(call DELFILE, $(SDKDIR)/workerspks/$(SPK)) + $(call CLEAN) + +ROOTDEPPATH = --dep-path . $(foreach d,$(INCDIRS), --dep-path $(d)) + +.depend: + @$(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(CSRCS) >Make.dep + @touch $@ + +depend: .depend + +# Rules for building worker support library + +libdepend: + $(Q) $(MAKE) -C $(WORKER_DIR) TOPDIR="$(TOPDIR)" SDKDIR="$(SDKDIR)" depend + +$(WORKER_LIB): libdepend + $(Q) $(MAKE) -C $(WORKER_DIR) TOPDIR="$(TOPDIR)" SDKDIR="$(SDKDIR)" libasmpw$(LIBEXT) + +context: + +-include Make.dep + +else # ($(BUILD_EXECUTE),1) + +clean: + +distclean: + +endif # ($(BUILD_EXECUTE),1) diff --git a/sdk/modules/audiolite/worker/common/mkfiles/cmsis.mk b/sdk/modules/audiolite/worker/common/mkfiles/cmsis.mk new file mode 100644 index 000000000..c4085253a --- /dev/null +++ b/sdk/modules/audiolite/worker/common/mkfiles/cmsis.mk @@ -0,0 +1,13 @@ +CMSISDIR = $(SDKDIR)$(DELIM)..$(DELIM)externals$(DELIM)cmsis +CMSIS_DSP_DIR = $(CMSISDIR)$(DELIM)dsp + +# Setup to build and linking CMSIS DSP library + +include $(CMSISDIR)/LibIncludes.mk + +CMSIS_DSP_LIB = $(CMSIS_DSP_DIR)$(DELIM)libarm_cortexM4lf_math$(LIBEXT) +LDLIBPATH += -L $(CMSIS_DSP_DIR) +LDLIBS += -larm_cortexM4lf_math + +$(CMSIS_DSP_LIB): + $(Q) $(MAKE) -C $(CMSIS_DSP_DIR) TOPDIR="$(TOPDIR)" SDKDIR="$(SDKDIR)" APPDIR="$(APPDIR)" diff --git a/sdk/modules/audiolite/worker/common/mkfiles/resampler.mk b/sdk/modules/audiolite/worker/common/mkfiles/resampler.mk new file mode 100644 index 000000000..1945edc8e --- /dev/null +++ b/sdk/modules/audiolite/worker/common/mkfiles/resampler.mk @@ -0,0 +1,11 @@ +ifneq ($(CONFIG_ASMP_WORKER_CMSIS),y) +$(error resampler uses CMSIS, + you must set CONFIG_ASMP_WORKER_CMSIS and CONFIG_EXTERNAL_CMSIS.) +endif + +SPEEXDSP_DIR = $(ALWORKER_COMMON)/../ext_libs/speexdsp_resample + +CSRCS += resample.c +VPATH_DIR += $(SPEEXDSP_DIR) +INCDIRS += $(SPEEXDSP_DIR) +CFLAGS += -DUSE_CMSIS diff --git a/sdk/modules/audiolite/worker/ext_libs/minimp3/minimp3.c b/sdk/modules/audiolite/worker/ext_libs/minimp3/minimp3.c index 40a512d3e..498fa4726 100644 --- a/sdk/modules/audiolite/worker/ext_libs/minimp3/minimp3.c +++ b/sdk/modules/audiolite/worker/ext_libs/minimp3/minimp3.c @@ -5,7 +5,6 @@ See . */ -#include #include #include "minimp3.h" diff --git a/sdk/modules/audiolite/worker/mp3dec/Makefile b/sdk/modules/audiolite/worker/mp3dec/Makefile index 20f630a8d..c032811ff 100644 --- a/sdk/modules/audiolite/worker/mp3dec/Makefile +++ b/sdk/modules/audiolite/worker/mp3dec/Makefile @@ -38,7 +38,7 @@ include $(APPDIR)/Make.defs ifeq ($(CONFIG_AUDIO_LITE_MP3DEC_SUBCORE_ELF),y) BUILD_EXECUTE = 1 -else ifeq ($(FORCE_BUILD),1) +else ifeq ($(CONFIG_AUDIO_LITE_MP3DEC_SUBCORE_SPK_BUILD),y) BUILD_EXECUTE = 1 else BUILD_EXECUTE = 0 @@ -47,7 +47,22 @@ endif ifeq ($(BUILD_EXECUTE),1) BIN = mp3dec +SPK = $(BIN).spk + +ifeq ($(CONFIG_AUDIO_LITE_MP3DEC_SUBCORE_ELF),y) all: depend $(BIN) +endif + +ifeq ($(CONFIG_AUDIO_LITE_MP3DEC_SUBCORE_SPK_BUILD),y) +all: depend $(SPK) +endif + +# For SPK tools + +MKSPK_TOOLDIR = $(TOPDIR)/tools/cxd56 +MKSPK_MKFILE = $(MKSPK_TOOLDIR)/Makefile.host +MKSPK_TOOL = $(MKSPK_TOOLDIR)/mkspk +MKSPK_TOOL_OPT = -c 2 # Setup to build and linking worker support library @@ -73,6 +88,7 @@ MINIMP3_DIR = ../ext_libs/minimp3 SPEEXDSP_DIR = ../ext_libs/speexdsp_resample CSRCS = entry.c mp3dec_main.c +CSRCS += sprmp3_debug.c CSRCS += sprmp3_msghandler.c CSRCS += sprmp3_sendback.c CSRCS += alworker_comm.c @@ -81,11 +97,21 @@ CSRCS += minimp3_ex.c CSRCS += resample.c CFLAGS += -DUSE_CMSIS -DBUILD_TGT_ASMPWORKER +ifneq ($(CONFIG_AUDIO_LITE_MP3DEC_SUBCORE_DEBUG),) +CFLAGS += -DSPRMP3_DEBUG +ifneq ($(CONFIG_AUDIO_LITE_MP3DEC_SUBCORE_DEBUG_DETAIL),) +CFLAGS += -DSPRMP3_DEBUG_DETAIL +endif +endif + VPATH = $(COMMON_DIR) $(MINIMP3_DIR) $(SPEEXDSP_DIR) DELTGT_FILES = $(CSRCS:.c=.o) +ARCHSRCDIR = $(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src + INCDIRS = $(COMMON_DIR) $(MINIMP3_DIR) $(SPEEXDSP_DIR) $(AUDIOLITE_DIR)/../include +INCDIRS += $(ARCHSRCDIR)$(DELIM)chip $(ARCHSRCDIR)$(DELIM)common CFLAGS += -O3 ifeq ($(WINTOOL),y) @@ -116,10 +142,20 @@ $(BIN): $(COBJS) $(AOBJS) | $(WORKER_LIB) $(CMSIS_DSP_LIB) $(Q) cp $(BIN) $(BIN).debug.elf $(Q) $(STRIP) -d $(BIN) +$(MKSPK_TOOL): + @$(MAKE) -C $(MKSPK_TOOLDIR) -f $(MKSPK_MKFILE) TOPDIR="$(TOPDIR)" + +# SDKDIR="$(SDKDIR)" APPDIR="$(APPDIR)" CROSSDEV=$(CROSSDEV) + +$(SPK): $(MKSPK_TOOL) $(BIN) + @echo "MKSPK: $@" + $(MKSPK_TOOL) $(MKSPK_TOOL_OPT) $(BIN) $(BIN) $(SPK) + clean: $(call DELFILE, $(BIN)) $(call DELFILE, $(BIN).debug.elf) $(call DELFILE, $(DELTGT_FILES)) + $(call DELFILE, $(SPK)) $(call CLEAN) ROOTDEPPATH = --dep-path . $(foreach d,$(INCDIRS), --dep-path $(d)) diff --git a/sdk/modules/audiolite/worker/mp3dec/mp3dec_main.c b/sdk/modules/audiolite/worker/mp3dec/mp3dec_main.c index a6c694151..2556baedf 100644 --- a/sdk/modules/audiolite/worker/mp3dec/mp3dec_main.c +++ b/sdk/modules/audiolite/worker/mp3dec/mp3dec_main.c @@ -45,9 +45,7 @@ #include "sprmp3_msghandler.h" #include "sprmp3_sendback.h" -#ifdef SPRMP3_DEBUG #include "sprmp3_debug.h" -#endif #ifdef ENABME_PERFORMANCE #include @@ -94,7 +92,7 @@ static struct state_proc_s state_procs[] = [SPRMP3_STATE_FILLUPREMAIN] = {exec_fillremstate, 1}, [SPRMP3_STATE_WAITIN] = {exec_waitinstate, 1}, [SPRMP3_STATE_WAITINREMAIN] = {exec_winremstate, 1}, - [SPRMP3_STATE_ENDING] = {exec_endingstate, 1} + [SPRMP3_STATE_ENDING] = {exec_endingstate, 2} }; static sprmp3_sys_t g_sys; @@ -207,7 +205,7 @@ static int exec_endingstate(sprmp3_t *inst, sprmp3_outmemqueue_t *outq) if (!(outq->done & mask)) { - if (is_decode_done(inst)) + if (is_decode_done(inst) && outq->filled_size == 0) { send_framedone(inst->id); reset_instance(inst); @@ -431,9 +429,7 @@ static int initialize_framecache(sprmp3_t *inst) if (fill_tagsize(inst) == 0) { -#ifdef SPRMP3_DEBUG sprmp3_dprintf("fill_tagsize() error\n"); -#endif return SPRMP3_STATE_ERROR; } @@ -441,10 +437,8 @@ static int initialize_framecache(sprmp3_t *inst) if (inst->fcache.fillsize != MINIMP3_ID3_DETECT_SIZE) { -#ifdef SPRMP3_DEBUG sprmp3_dprintf("fillsize is not equal ID3 SIZE : %d\n", inst->fcache.fillsize); -#endif return SPRMP3_STATE_ERROR; } @@ -857,9 +851,7 @@ static int exec_decodestate(sprmp3_t *inst, sprmp3_outmemqueue_t *outq) inst->tgtcache.decsize = inst->tgtcache.remofst; outq->done |= SPRMP3_OUTDONE(inst); inst->omem_wofst = 0; -#ifdef SPRMP3_DEBUG sprmp3_dprintf("Force the decode finish.\n"); -#endif return SPRMP3_STATE_ENDING; } else @@ -1112,7 +1104,7 @@ static bool all_player_done(sprmp3_t *insts, unsigned int done) for (i = 0; i < SPRMP3_MAX_INSTANCE; i++) { mask = 1 << insts->id; - if (state_procs[insts->state].playing && !(mask & done)) + if (state_procs[insts->state].playing == 1 && !(mask & done)) { return false; } @@ -1175,7 +1167,7 @@ static int deliver_decodedpcm(sprmp3_t *insts, sprmp3_outmemqueue_t *outq, break; } - return deliver_outpcm(outq); + return deliver_outpcm(outq, is_decode_done(insts) ? 1 : 0); } } @@ -1198,17 +1190,14 @@ int mp3dec_main(void) dbg_init_compare(); #endif -#ifdef SPRMP3_DEBUG print_status(&g_sys); -#endif - send_bootmsg(); + send_bootmsg(NULL); while (g_sys.system_state != SPRMP3_SYSSTATE_TERM) { -#ifdef SPRMP3_DEBUG sprmp3_dprintf("\n::::::::: Start Loop ::::::::::\n"); -#endif + print_status(&g_sys); if (g_sys.system_state == SPRMP3_SYSSTATE_STOP) { sprmp3_pollmessage(&g_sys, 1); @@ -1216,29 +1205,22 @@ int mp3dec_main(void) else { sprmp3_pollmessage(&g_sys, 0); -#ifdef SPRMP3_DEBUG print_status(&g_sys); print_buffer_status(&g_sys); -#endif if (g_sys.system_state != SPRMP3_SYSSTATE_TERM) { exec_playing(&g_sys); -#ifdef SPRMP3_DEBUG print_buffer_status(&g_sys); -#endif if (g_sys.system_state == SPRMP3_SYSSTATE_PAUSE || !exist_playing(g_sys.insts)) { -#ifdef SPRMP3_DEBUG sprmp3_dprintf("Just Deliver PCM..\n"); -#endif - deliver_outpcm(&g_sys.outqueue); + deliver_outpcm(&g_sys.outqueue, + is_decode_done(g_sys.insts) ? 1 : 0); } else { -#ifdef SPRMP3_DEBUG sprmp3_dprintf("Deliver PCM if possible..\n"); -#endif deliver_decodedpcm(g_sys.insts, &g_sys.outqueue, &g_sys.sys_gain, diff --git a/sdk/modules/audiolite/worker/mp3dec/sprmp3_debug.c b/sdk/modules/audiolite/worker/mp3dec/sprmp3_debug.c index 618eeb346..32c12ee95 100644 --- a/sdk/modules/audiolite/worker/mp3dec/sprmp3_debug.c +++ b/sdk/modules/audiolite/worker/mp3dec/sprmp3_debug.c @@ -37,8 +37,11 @@ * Included Files ****************************************************************************/ -#include -#include +#ifdef BUILD_TGT_ASMPWORKER +# include +#else +# include +#endif #include "sprmp3_debug.h" @@ -49,6 +52,8 @@ #ifdef SPRMP3_DEBUG #ifdef SPRMP3_DEBUG_COMPARE +#include + static int dbg_framesz; static int dbg_frame_ofst; static unsigned char *dbg_mp3framemem; @@ -102,7 +107,8 @@ int dbg_init_compare(void) } #endif -const char *inststatelog(int state) +#ifdef SPRMP3_DEBUG_DETAIL +static const char *inststatelog(int state) { switch (state) { @@ -120,7 +126,7 @@ const char *inststatelog(int state) return "Unknown"; } -const char *statelog(int state) +static const char *statelog(int state) { switch (state) { @@ -142,13 +148,13 @@ void print_status(sprmp3_sys_t *sys) inst = &sys->insts[0]; printf("==== System State : %s =====\n", statelog(sys->system_state)); - printf(" OutQueue: Free:%ld, Queued:%ld\n", + printf(" OutQueue: Free:%d, Queued:%d \n", sq_count(&sys->outqueue.free), sq_count(&sys->outqueue.queued)); for (i = 0; i < SPRMP3_MAX_INSTANCE; i++) { - printf(" Inst:%d Status:%s, Queue:," + printf(" Inst:%d Status:%s, Queue:," " Gain:%f\n", inst->id, inststatelog(inst->state), sq_count(&inst->fqueue.free), @@ -201,5 +207,6 @@ void print_buffer_status(sprmp3_sys_t *sys) inst++; } } +#endif /* SPRMP3_DEBUG_DETAIL */ #endif /* SPRMP3_DEBUG */ diff --git a/sdk/modules/audiolite/worker/mp3dec/sprmp3_debug.h b/sdk/modules/audiolite/worker/mp3dec/sprmp3_debug.h index bc9b690d2..260382b42 100644 --- a/sdk/modules/audiolite/worker/mp3dec/sprmp3_debug.h +++ b/sdk/modules/audiolite/worker/mp3dec/sprmp3_debug.h @@ -40,14 +40,29 @@ * Included Files ****************************************************************************/ -#include +#ifdef BUILD_TGT_ASMPWORKER +# include +#else +# include +#endif + #include "minimp3_spresense.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -#define sprmp3_dprintf(...) printf(__VA_ARGS__) +#ifdef SPRMP3_DEBUG +# define sprmp3_dprintf(...) printf(__VA_ARGS__) +# ifndef SPRMP3_DEBUG_DETAIL +# define print_status(s) +# define print_buffer_status(s) +# endif +#else +# define sprmp3_dprintf(...) +# define print_status(s) +# define print_buffer_status(s) +#endif /**************************************************************************** * Public Function Prototypes @@ -58,11 +73,18 @@ extern "C" { #endif /* __cplusplus */ +#ifdef SPRMP3_DEBUG + +#ifdef SPRMP3_DEBUG_COMPARE int dbg_load_mp3frame(const char *fname, unsigned char **fmem); -const char *inststatelog(int state); -const char *statelog(int state); +#endif + +#ifdef SPRMP3_DEBUG_DETAIL void print_status(sprmp3_sys_t *sys); void print_buffer_status(sprmp3_sys_t *sys); +#endif + +#endif #ifdef __cplusplus } diff --git a/sdk/modules/audiolite/worker/mp3dec/sprmp3_msghandler.c b/sdk/modules/audiolite/worker/mp3dec/sprmp3_msghandler.c index 52e74a46d..e8c370c8a 100644 --- a/sdk/modules/audiolite/worker/mp3dec/sprmp3_msghandler.c +++ b/sdk/modules/audiolite/worker/mp3dec/sprmp3_msghandler.c @@ -46,9 +46,7 @@ #include "sprmp3_msghandler.h" #include "sprmp3_sendback.h" -#ifdef SPRMP3_DEBUG #include "sprmp3_debug.h" -#endif /**************************************************************************** * Public Data @@ -68,7 +66,7 @@ static void release_all_mem(sprmp3_sys_t *sys) while (sq_peek(&sys->outqueue.queued) != NULL) { - deliver_outpcm(&sys->outqueue); + deliver_outpcm(&sys->outqueue, 0); } for (i = 0; i < SPRMP3_MAX_INSTANCE; i++) @@ -132,10 +130,7 @@ static void handle_system_msg(sprmp3_sys_t *sys, case AL_COMM_MSGCODESYS_TERM: -#ifdef SPRMP3_DEBUG sprmp3_dprintf("[RCV] Terminate\n"); -#endif - sys->system_state = SPRMP3_SYSSTATE_TERM; release_all_mem(sys); break; @@ -307,6 +302,8 @@ static void handle_message(sprmp3_sys_t *sys, al_comm_msghdr_t hdr, al_comm_msgopt_t *opt) { + sprmp3_dprintf("[mp3dec] GRP:%d TYP:%d COD:%d OPT:%d\n", + hdr.grp, hdr.type, hdr.code, hdr.opt); switch (hdr.grp) { case AL_COMM_MESSAGE_SYS: diff --git a/sdk/modules/audiolite/worker/mp3dec/sprmp3_sendback.c b/sdk/modules/audiolite/worker/mp3dec/sprmp3_sendback.c index 1af4297bb..21c2dfc2e 100644 --- a/sdk/modules/audiolite/worker/mp3dec/sprmp3_sendback.c +++ b/sdk/modules/audiolite/worker/mp3dec/sprmp3_sendback.c @@ -113,7 +113,7 @@ int send_errormsg(int id, int errcode) /*** name: send_bootmsg */ -int send_bootmsg(void) +int send_bootmsg(void *d) { al_comm_msghdr_t hdr; al_comm_msgopt_t opt; @@ -122,6 +122,24 @@ int send_bootmsg(void) hdr.type = AL_COMM_MSGTYPE_ASYNC; hdr.code = AL_COMM_MSGCODESYS_BOOT; hdr.opt = AL_MP3DECWORKER_VERSION; + opt.addr = (unsigned char *)alworker_addr_convert(d); + +#ifdef SPRMP3_DEBUG + sprmp3_dprintf("[MSG] BootUp\n"); +#endif + + return al_send_message(&g_mp3dec_task, hdr, &opt); +} + +int send_debug(unsigned char hdr_opt) +{ + al_comm_msghdr_t hdr; + al_comm_msgopt_t opt; + + hdr.grp = AL_COMM_MESSAGE_SYS; + hdr.type = AL_COMM_MSGTYPE_ASYNC; + hdr.code = AL_COMM_MSGCODESYS_DBG; + hdr.opt = hdr_opt; #ifdef SPRMP3_DEBUG sprmp3_dprintf("[MSG] BootUp\n"); @@ -161,7 +179,7 @@ int release_framemem(int id, sprmp3_fmemqueue_t *queue) /*** name: deliver_outpcm */ -int deliver_outpcm(sprmp3_outmemqueue_t *outq) +int deliver_outpcm(sprmp3_outmemqueue_t *outq, int eof) { al_comm_msghdr_t hdr; al_comm_msgopt_t opt; @@ -179,7 +197,7 @@ int deliver_outpcm(sprmp3_outmemqueue_t *outq) opt.addr = mem->addr; opt.size = (outq->mode == SPRMP3_MODE_JUSTDECODE) ? outq->filled_size : mem->size; - opt.eof = 0; + opt.eof = eof; sq_addlast((sq_entry_t *)mem, &outq->free); outq->done = 0; diff --git a/sdk/modules/audiolite/worker/mp3dec/sprmp3_sendback.h b/sdk/modules/audiolite/worker/mp3dec/sprmp3_sendback.h index 4dd4bc128..bed805118 100644 --- a/sdk/modules/audiolite/worker/mp3dec/sprmp3_sendback.h +++ b/sdk/modules/audiolite/worker/mp3dec/sprmp3_sendback.h @@ -54,9 +54,10 @@ extern "C" int send_frameinfo(int id, mp3dec_frame_info_t *info); int send_framedone(int id); int send_errormsg(int id, int errcode); -int send_bootmsg(void); +int send_bootmsg(void *d); +int send_debug(unsigned char opt); int release_framemem(int id, sprmp3_fmemqueue_t *queue); -int deliver_outpcm(sprmp3_outmemqueue_t *outq); +int deliver_outpcm(sprmp3_outmemqueue_t *outq, int eof); #ifdef __cplusplus } diff --git a/sdk/modules/bluetooth/bluetooth_common.c b/sdk/modules/bluetooth/bluetooth_common.c index 509cbd553..7e1febb0f 100644 --- a/sdk/modules/bluetooth/bluetooth_common.c +++ b/sdk/modules/bluetooth/bluetooth_common.c @@ -1,7 +1,7 @@ /**************************************************************************** * modules/bluetooth/bluetooth_common.c * - * Copyright 2018, 2023 Sony Semiconductor Solutions Corporation + * Copyright 2018, 2023, 2024 Sony Semiconductor Solutions Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -69,7 +69,8 @@ static struct bt_common_state_s g_bt_common_state = .bt_name = CONFIG_BLUETOOTH_NAME, .ble_name = CONFIG_BLUETOOTH_LE_NAME, .bt_addr = {{0x20, 0x70, 0x3A, 0x10, 0x00, 0x01}}, - .ble_addr = {{0x20, 0x70, 0x3A, 0x10, 0x00, 0x01}} + .ble_addr = {{0x20, 0x70, 0x3A, 0x10, 0x00, 0x01}}, + .ble_addr_type = BLE_ADDRTYPE_RAND_STATIC }; static struct bt_acl_state_s g_bt_acl_state = @@ -870,8 +871,8 @@ int bt_common_event_handler(struct bt_event_t *bt_event) * Name: ble_set_address * * Description: - * Set Bluetooth LE module address - * This is Spresense side address and should be call before bt_enable. + * Set Bluetooth LE module address of the random static address type. + * This is Spresense side address and should be called before bt_enable. * ****************************************************************************/ @@ -881,14 +882,52 @@ int ble_set_address(BT_ADDR *addr) if (!addr) { - _err("%s [BLE][Common] Set local BT address failed(addr not set).\n", __func__); + _err("%s [BLE][Common] Set own BLE address failed.\n", __func__); return BT_FAIL; } + g_bt_common_state.ble_addr_type = BLE_ADDRTYPE_RAND_STATIC; memcpy(&g_bt_common_state.ble_addr, addr, sizeof(BT_ADDR)); return ret; } +/**************************************************************************** + * Name: ble_set_public_address + * + * Description: + * Set Bluetooth LE module address of the public address type. + * This is Spresense side address and should be called before bt_enable. + * + ****************************************************************************/ + +int ble_set_public_address(BT_ADDR *addr) +{ + int ret = BT_SUCCESS; + + if (!addr) + { + _err("%s [BLE][Common] Set own BLE public address failed.\n", __func__); + return BT_FAIL; + } + + g_bt_common_state.ble_addr_type = BLE_ADDRTYPE_PUBLIC; + memcpy(&g_bt_common_state.ble_addr, addr, sizeof(BT_ADDR)); + return ret; +} + +/**************************************************************************** + * Name: ble_get_address_type + * + * Description: + * Get Bluetooth LE module address type + * + ****************************************************************************/ + +uint8_t ble_get_address_type(void) +{ + return g_bt_common_state.ble_addr_type; +} + /**************************************************************************** * Name: ble_get_address * @@ -916,7 +955,7 @@ int ble_get_address(BT_ADDR *addr) * * Description: * Set Bluetooth LE module name - * This name visible for other devices and should be call before bt_enable. + * This name visible for other devices and should be called before bt_enable. * ****************************************************************************/ @@ -962,6 +1001,32 @@ int ble_get_name(char *name) return ret; } +/**************************************************************************** + * Name: ble_set_appearance + * + * Description: + * Set Bluetooth LE module appearance + * + ****************************************************************************/ + +int ble_set_appearance(BLE_APPEARANCE appearance) +{ + int ret = BT_FAIL; + struct ble_hal_common_ops_s *ble_hal_common_ops = g_bt_common_state.ble_hal_common_ops; + + if (ble_hal_common_ops && ble_hal_common_ops->setAppearance) + { + ret = ble_hal_common_ops->setAppearance(appearance); + + if (ret != BT_SUCCESS) + { + _err("%s [BLE][Common] Set appearance failed.\n", __func__); + } + } + + return ret; +} + /**************************************************************************** * Name: ble_enable * @@ -979,7 +1044,6 @@ int ble_enable(void) if (ble_hal_common_ops && ble_hal_common_ops->setDevName && ble_hal_common_ops->setDevAddr && - ble_hal_common_ops->setAppearance && ble_hal_common_ops->setPPCP) { ret = ble_hal_common_ops->setDevName(g_bt_common_state.ble_name); @@ -990,7 +1054,8 @@ int ble_enable(void) return ret; } - ret = ble_hal_common_ops->setDevAddr(&g_bt_common_state.ble_addr); + ret = ble_hal_common_ops->setDevAddr(&g_bt_common_state.ble_addr, + g_bt_common_state.ble_addr_type); if (ret != BT_SUCCESS) { @@ -998,14 +1063,6 @@ int ble_enable(void) return ret; } - ret = ble_hal_common_ops->setAppearance(BLE_APPEARANCE_GENERIC_PHONE); - - if (ret != BT_SUCCESS) - { - _err("%s [BLE][Common] BLE set appearance failed.\n", __func__); - return ret; - } - ret = ble_hal_common_ops->setPPCP(ppcp); if (ret != BT_SUCCESS) @@ -1291,6 +1348,60 @@ int ble_get_negotiated_mtusize(uint16_t handle) return ret; } +int ble_set_tx_power(int8_t tx_power) +{ + int ret = BT_SUCCESS; + struct ble_hal_common_ops_s *ops = g_bt_common_state.ble_hal_common_ops; + + if (ops && ops->setTxPower) + { + ret = ops->setTxPower(tx_power); + } + else + { + _err("%s [BLE][Common] Not supported.\n", __func__); + return BT_FAIL; + } + + return ret; +} + +int ble_set_scan_param(struct ble_scan_param_s *param) +{ + int ret = BT_SUCCESS; + struct ble_hal_common_ops_s *ops = g_bt_common_state.ble_hal_common_ops; + + if (ops && ops->setScanParam) + { + ret = ops->setScanParam(param); + } + else + { + _err("%s [BLE][Common] Not supported.\n", __func__); + return BT_FAIL; + } + + return ret; +} + +int ble_set_conn_param(struct ble_conn_param_s *param) +{ + int ret = BT_SUCCESS; + struct ble_hal_common_ops_s *ops = g_bt_common_state.ble_hal_common_ops; + + if (ops && ops->setConnParam) + { + ret = ops->setConnParam(param); + } + else + { + _err("%s [BLE][Common] Not supported.\n", __func__); + return BT_FAIL; + } + + return ret; +} + /**************************************************************************** * Name: ble_register_common_cb * @@ -1318,7 +1429,7 @@ int ble_register_common_cb(struct ble_common_ops_s *ble_common_ops) * * Description: * Bluetooth LE common function HAL register - * This is Spresense side address and should be call before bt_enable. + * This is Spresense side address and should be called before bt_enable. * ****************************************************************************/ @@ -1389,7 +1500,7 @@ int ble_parse_advertising_data(BLE_AD_TYPE target, uint8_t adv_len, struct bt_eir_s *eir) { - int i = 0; + int i = 2; /* raw advertising data starts from the 3rd offset */ uint8_t len; uint8_t type; uint8_t *data; @@ -1407,8 +1518,6 @@ int ble_parse_advertising_data(BLE_AD_TYPE target, return BT_SUCCESS; } - i++; - while (i < adv_len) { /* For calculation of data length, diff --git a/sdk/modules/bluetooth/bluetooth_le_gatt.c b/sdk/modules/bluetooth/bluetooth_le_gatt.c index 5cc01e17d..f8bc4942f 100644 --- a/sdk/modules/bluetooth/bluetooth_le_gatt.c +++ b/sdk/modules/bluetooth/bluetooth_le_gatt.c @@ -945,3 +945,30 @@ int ble_descriptor_write(uint16_t conn_handle, return ret; } + +/**************************************************************************** + * Name: ble_set_vendor_uuid + * + * Description: + * Set vendor specific UUID. + * This API allows the vendor specific UUID to be discovered. + * + ****************************************************************************/ + +int ble_set_vendor_uuid(BLE_UUID *uuid) +{ + int ret = BT_SUCCESS; + struct ble_hal_gattc_ops_s *ops = &g_ble_gatt_state.ble_hal_gatt_ops->gattc; + + if (ops && ops->set_vendor_uuid) + { + ret = ops->set_vendor_uuid(uuid); + } + else + { + _err("%s [BLE][GATT] Not supported.\n", __func__); + return BT_FAIL; + } + + return ret; +} diff --git a/sdk/modules/bluetooth/bluetooth_le_util.c b/sdk/modules/bluetooth/bluetooth_le_util.c index 77436307c..3593d241e 100755 --- a/sdk/modules/bluetooth/bluetooth_le_util.c +++ b/sdk/modules/bluetooth/bluetooth_le_util.c @@ -1,7 +1,7 @@ /**************************************************************************** * sdk/modules/bluetooth/bluetooth_le_util.c * - * Copyright 2023 Sony Semiconductor Solutions Corporation + * Copyright 2023, 2024 Sony Semiconductor Solutions Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -535,13 +535,15 @@ int bleutil_get_devicename(uint8_t *data, uint8_t len, char *devname) if (ble_parse_advertising_data(BLE_AD_TYPE_COMPLETE_LOCAL_NAME, data, len, &eir) == BT_SUCCESS) { - memcpy(devname, eir.data, sizeof(eir.data)); + memcpy(devname, eir.data, eir.len); + devname[eir.len] = '\0'; return 1; } else if(ble_parse_advertising_data(BLE_AD_TYPE_SHORT_LOCAL_NAME, data, len, &eir) == BT_SUCCESS) { - memcpy(devname, eir.data, sizeof(eir.data)); + memcpy(devname, eir.data, eir.len); + devname[eir.len] = '\0'; return 1; } @@ -563,10 +565,21 @@ int bleutil_get_devicename(uint8_t *data, uint8_t len, char *devname) uint8_t bleutil_get_addrtype(uint8_t *data, uint8_t len) { - struct bt_eir_s eir; - ble_parse_advertising_data(BLE_AD_TYPE_ADDRESS_TYPE, - data, len, &eir); - return eir.data[0]; + return (BLE_ADDRESS_TYPE)data[0]; +} + +/* name: bleutil_get_rssi + * Get BLE RSSI value from advertising data + * + * data [in] : Advertising data + * len [in] : Advertising data length in bytes + * + * Return : BLE RSSI value for advertising + */ + +int8_t bleutil_get_rssi(uint8_t *data, uint8_t len) +{ + return (int8_t)data[1]; } /* name: bleutil_get_advertising_flags diff --git a/sdk/modules/bluetooth/hal/bcm20706/bcm20706_ble_common.c b/sdk/modules/bluetooth/hal/bcm20706/bcm20706_ble_common.c index b80b5f29b..361613019 100644 --- a/sdk/modules/bluetooth/hal/bcm20706/bcm20706_ble_common.c +++ b/sdk/modules/bluetooth/hal/bcm20706/bcm20706_ble_common.c @@ -1,7 +1,7 @@ /**************************************************************************** - * modules/bluetooth/hal/bcm20706/manager/bt_uart_manager.c + * modules/bluetooth/hal/bcm20706/bcm20706_ble_common.c * - * Copyright 2018 Sony Semiconductor Solutions Corporation + * Copyright 2018, 2024 Sony Semiconductor Solutions Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -86,7 +86,7 @@ extern bleGapMem *bleGetGapMem(void); * Private Function Prototypes ****************************************************************************/ -static int bcm20706_ble_set_dev_addr(BT_ADDR *addr); +static int bcm20706_ble_set_dev_addr(BT_ADDR *addr, uint8_t type); static int bcm20706_ble_set_dev_name(char *name); static int bcm20706_ble_set_appearance(BLE_APPEARANCE appearance); static int bcm20706_ble_set_ppcp(BLE_CONN_PARAMS ppcp); @@ -197,7 +197,7 @@ static int32_t set_adv_data(void) * ****************************************************************************/ -static int bcm20706_ble_set_dev_addr(BT_ADDR *addr) +static int bcm20706_ble_set_dev_addr(BT_ADDR *addr, uint8_t type) { int ret = BT_SUCCESS; @@ -226,7 +226,7 @@ static int bcm20706_ble_set_dev_name(char *name) nameSize = strlen(name); - /* If invalid size, retrun NG */ + /* If invalid size, return error */ if (!name || nameSize > BT_MAX_NAME_LEN) { diff --git a/sdk/modules/bluetooth/hal/bcm20706/include/ble/ble_gattc.h b/sdk/modules/bluetooth/hal/bcm20706/include/ble/ble_gattc.h index c5489a862..7f4443543 100644 --- a/sdk/modules/bluetooth/hal/bcm20706/include/ble/ble_gattc.h +++ b/sdk/modules/bluetooth/hal/bcm20706/include/ble/ble_gattc.h @@ -54,6 +54,7 @@ #include #include +#include /**************************************************************************** * Pre-processor Definitions @@ -63,9 +64,6 @@ * @{ */ - -#define BLE_DB_DISCOVERY_MAX_SRV 3 /**< Support Max services */ -#define BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV 4 /**< Support Max characteristics per service */ #ifndef CONFIG_NRF51822 #define MAX_VAL_DATA_LENGTH 512 /**< Max value data length. */ #else diff --git a/sdk/modules/bluetooth/hal/bcm20706/include/queue.h b/sdk/modules/bluetooth/hal/bcm20706/include/queue.h deleted file mode 100644 index 37bd61924..000000000 --- a/sdk/modules/bluetooth/hal/bcm20706/include/queue.h +++ /dev/null @@ -1,851 +0,0 @@ -/* $NetBSD: queue.h,v 1.68 2014/11/19 08:10:01 uebayasi Exp $ */ - -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)queue.h 8.5 (Berkeley) 8/20/94 - */ - -#ifndef _SYS_QUEUE_H_ -#define _SYS_QUEUE_H_ - -/* - * This file defines five types of data structures: singly-linked lists, - * lists, simple queues, tail queues, and circular queues. - * - * A singly-linked list is headed by a single forward pointer. The - * elements are singly linked for minimum space and pointer manipulation - * overhead at the expense of O(n) removal for arbitrary elements. New - * elements can be added to the list after an existing element or at the - * head of the list. Elements being removed from the head of the list - * should use the explicit macro for this purpose for optimum - * efficiency. A singly-linked list may only be traversed in the forward - * direction. Singly-linked lists are ideal for applications with large - * datasets and few or no removals or for implementing a LIFO queue. - * - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before - * or after an existing element or at the head of the list. A list - * may only be traversed in the forward direction. - * - * A simple queue is headed by a pair of pointers, one the head of the - * list and the other to the tail of the list. The elements are singly - * linked to save space, so elements can only be removed from the - * head of the list. New elements can be added to the list after - * an existing element, at the head of the list, or at the end of the - * list. A simple queue may only be traversed in the forward direction. - * - * A tail queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or - * after an existing element, at the head of the list, or at the end of - * the list. A tail queue may be traversed in either direction. - * - * A circle queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or after - * an existing element, at the head of the list, or at the end of the list. - * A circle queue may be traversed in either direction, but has a more - * complex end of list detection. - * - * For details on the use of these macros, see the queue(3) manual page. - */ - -/* - * Include the definition of NULL only on NetBSD because sys/null.h - * is not available elsewhere. This conditional makes the header - * portable and it can simply be dropped verbatim into any system. - * The caveat is that on other systems some other header - * must provide NULL before the macros can be used. - */ -#ifdef __NetBSD__ -#include -#endif - -#if defined(QUEUEDEBUG) -# if defined(_KERNEL) -# define QUEUEDEBUG_ABORT(...) panic(__VA_ARGS__) -# else -# include -# define QUEUEDEBUG_ABORT(...) err(1, __VA_ARGS__) -# endif -#endif - -/* - * Singly-linked List definitions. - */ -#define SLIST_HEAD(name, type) \ -struct name { \ - struct type *slh_first; /* first element */ \ -} - -#define SLIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define SLIST_ENTRY(type) \ -struct { \ - struct type *sle_next; /* next element */ \ -} - -/* - * Singly-linked List access methods. - */ -#define SLIST_FIRST(head) ((head)->slh_first) -#define SLIST_END(head) NULL -#define SLIST_EMPTY(head) ((head)->slh_first == NULL) -#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) - -#define SLIST_FOREACH(var, head, field) \ - for((var) = (head)->slh_first; \ - (var) != SLIST_END(head); \ - (var) = (var)->field.sle_next) - -#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = SLIST_FIRST((head)); \ - (var) != SLIST_END(head) && \ - ((tvar) = SLIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -/* - * Singly-linked List functions. - */ -#define SLIST_INIT(head) do { \ - (head)->slh_first = SLIST_END(head); \ -} while (/*CONSTCOND*/0) - -#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ - (elm)->field.sle_next = (slistelm)->field.sle_next; \ - (slistelm)->field.sle_next = (elm); \ -} while (/*CONSTCOND*/0) - -#define SLIST_INSERT_HEAD(head, elm, field) do { \ - (elm)->field.sle_next = (head)->slh_first; \ - (head)->slh_first = (elm); \ -} while (/*CONSTCOND*/0) - -#define SLIST_REMOVE_AFTER(slistelm, field) do { \ - (slistelm)->field.sle_next = \ - SLIST_NEXT(SLIST_NEXT((slistelm), field), field); \ -} while (/*CONSTCOND*/0) - -#define SLIST_REMOVE_HEAD(head, field) do { \ - (head)->slh_first = (head)->slh_first->field.sle_next; \ -} while (/*CONSTCOND*/0) - -#define SLIST_REMOVE(head, elm, type, field) do { \ - if ((head)->slh_first == (elm)) { \ - SLIST_REMOVE_HEAD((head), field); \ - } \ - else { \ - struct type *curelm = (head)->slh_first; \ - while(curelm->field.sle_next != (elm)) \ - curelm = curelm->field.sle_next; \ - curelm->field.sle_next = \ - curelm->field.sle_next->field.sle_next; \ - } \ -} while (/*CONSTCOND*/0) - - -/* - * List definitions. - */ -#define LIST_HEAD(name, type) \ -struct name { \ - struct type *lh_first; /* first element */ \ -} - -#define LIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define LIST_ENTRY(type) \ -struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ -} - -/* - * List access methods. - */ -#define LIST_FIRST(head) ((head)->lh_first) -#define LIST_END(head) NULL -#define LIST_EMPTY(head) ((head)->lh_first == LIST_END(head)) -#define LIST_NEXT(elm, field) ((elm)->field.le_next) - -#define LIST_FOREACH(var, head, field) \ - for ((var) = ((head)->lh_first); \ - (var) != LIST_END(head); \ - (var) = ((var)->field.le_next)) - -#define LIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = LIST_FIRST((head)); \ - (var) != LIST_END(head) && \ - ((tvar) = LIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define LIST_MOVE(head1, head2) do { \ - LIST_INIT((head2)); \ - if (!LIST_EMPTY((head1))) { \ - (head2)->lh_first = (head1)->lh_first; \ - LIST_INIT((head1)); \ - } \ -} while (/*CONSTCOND*/0) - -/* - * List functions. - */ -#if defined(QUEUEDEBUG) -#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) \ - if ((head)->lh_first && \ - (head)->lh_first->field.le_prev != &(head)->lh_first) \ - QUEUEDEBUG_ABORT("LIST_INSERT_HEAD %p %s:%d", (head), \ - __FILE__, __LINE__); -#define QUEUEDEBUG_LIST_OP(elm, field) \ - if ((elm)->field.le_next && \ - (elm)->field.le_next->field.le_prev != \ - &(elm)->field.le_next) \ - QUEUEDEBUG_ABORT("LIST_* forw %p %s:%d", (elm), \ - __FILE__, __LINE__); \ - if (*(elm)->field.le_prev != (elm)) \ - QUEUEDEBUG_ABORT("LIST_* back %p %s:%d", (elm), \ - __FILE__, __LINE__); -#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) \ - (elm)->field.le_next = (void *)1L; \ - (elm)->field.le_prev = (void *)1L; -#else -#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) -#define QUEUEDEBUG_LIST_OP(elm, field) -#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) -#endif - -#define LIST_INIT(head) do { \ - (head)->lh_first = LIST_END(head); \ -} while (/*CONSTCOND*/0) - -#define LIST_INSERT_AFTER(listelm, elm, field) do { \ - QUEUEDEBUG_LIST_OP((listelm), field) \ - if (((elm)->field.le_next = (listelm)->field.le_next) != \ - LIST_END(head)) \ - (listelm)->field.le_next->field.le_prev = \ - &(elm)->field.le_next; \ - (listelm)->field.le_next = (elm); \ - (elm)->field.le_prev = &(listelm)->field.le_next; \ -} while (/*CONSTCOND*/0) - -#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ - QUEUEDEBUG_LIST_OP((listelm), field) \ - (elm)->field.le_prev = (listelm)->field.le_prev; \ - (elm)->field.le_next = (listelm); \ - *(listelm)->field.le_prev = (elm); \ - (listelm)->field.le_prev = &(elm)->field.le_next; \ -} while (/*CONSTCOND*/0) - -#define LIST_INSERT_HEAD(head, elm, field) do { \ - QUEUEDEBUG_LIST_INSERT_HEAD((head), (elm), field) \ - if (((elm)->field.le_next = (head)->lh_first) != LIST_END(head))\ - (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ - (head)->lh_first = (elm); \ - (elm)->field.le_prev = &(head)->lh_first; \ -} while (/*CONSTCOND*/0) - -#define LIST_REMOVE(elm, field) do { \ - QUEUEDEBUG_LIST_OP((elm), field) \ - if ((elm)->field.le_next != NULL) \ - (elm)->field.le_next->field.le_prev = \ - (elm)->field.le_prev; \ - *(elm)->field.le_prev = (elm)->field.le_next; \ - QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \ -} while (/*CONSTCOND*/0) - -#define LIST_REPLACE(elm, elm2, field) do { \ - if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ - (elm2)->field.le_next->field.le_prev = \ - &(elm2)->field.le_next; \ - (elm2)->field.le_prev = (elm)->field.le_prev; \ - *(elm2)->field.le_prev = (elm2); \ - QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \ -} while (/*CONSTCOND*/0) - -/* - * Simple queue definitions. - */ -#define SIMPLEQ_HEAD(name, type) \ -struct name { \ - struct type *sqh_first; /* first element */ \ - struct type **sqh_last; /* addr of last next element */ \ -} - -#define SIMPLEQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).sqh_first } - -#define SIMPLEQ_ENTRY(type) \ -struct { \ - struct type *sqe_next; /* next element */ \ -} - -/* - * Simple queue access methods. - */ -#define SIMPLEQ_FIRST(head) ((head)->sqh_first) -#define SIMPLEQ_END(head) NULL -#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == SIMPLEQ_END(head)) -#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) - -#define SIMPLEQ_FOREACH(var, head, field) \ - for ((var) = ((head)->sqh_first); \ - (var) != SIMPLEQ_END(head); \ - (var) = ((var)->field.sqe_next)) - -#define SIMPLEQ_FOREACH_SAFE(var, head, field, next) \ - for ((var) = ((head)->sqh_first); \ - (var) != SIMPLEQ_END(head) && \ - ((next = ((var)->field.sqe_next)), 1); \ - (var) = (next)) - -/* - * Simple queue functions. - */ -#define SIMPLEQ_INIT(head) do { \ - (head)->sqh_first = NULL; \ - (head)->sqh_last = &(head)->sqh_first; \ -} while (/*CONSTCOND*/0) - -#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ - (head)->sqh_last = &(elm)->field.sqe_next; \ - (head)->sqh_first = (elm); \ -} while (/*CONSTCOND*/0) - -#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.sqe_next = NULL; \ - *(head)->sqh_last = (elm); \ - (head)->sqh_last = &(elm)->field.sqe_next; \ -} while (/*CONSTCOND*/0) - -#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ - if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ - (head)->sqh_last = &(elm)->field.sqe_next; \ - (listelm)->field.sqe_next = (elm); \ -} while (/*CONSTCOND*/0) - -#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ - if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ - (head)->sqh_last = &(head)->sqh_first; \ -} while (/*CONSTCOND*/0) - -#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ - if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \ - == NULL) \ - (head)->sqh_last = &(elm)->field.sqe_next; \ -} while (/*CONSTCOND*/0) - -#define SIMPLEQ_REMOVE(head, elm, type, field) do { \ - if ((head)->sqh_first == (elm)) { \ - SIMPLEQ_REMOVE_HEAD((head), field); \ - } else { \ - struct type *curelm = (head)->sqh_first; \ - while (curelm->field.sqe_next != (elm)) \ - curelm = curelm->field.sqe_next; \ - if ((curelm->field.sqe_next = \ - curelm->field.sqe_next->field.sqe_next) == NULL) \ - (head)->sqh_last = &(curelm)->field.sqe_next; \ - } \ -} while (/*CONSTCOND*/0) - -#define SIMPLEQ_CONCAT(head1, head2) do { \ - if (!SIMPLEQ_EMPTY((head2))) { \ - *(head1)->sqh_last = (head2)->sqh_first; \ - (head1)->sqh_last = (head2)->sqh_last; \ - SIMPLEQ_INIT((head2)); \ - } \ -} while (/*CONSTCOND*/0) - -#define SIMPLEQ_LAST(head, type, field) \ - (SIMPLEQ_EMPTY((head)) ? \ - NULL : \ - ((struct type *)(void *) \ - ((char *)((head)->sqh_last) - offsetof(struct type, field)))) - -/* - * Tail queue definitions. - */ -#define _TAILQ_HEAD(name, type, qual) \ -struct name { \ - qual type *tqh_first; /* first element */ \ - qual type *qual *tqh_last; /* addr of last next element */ \ -} -#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,) - -#define TAILQ_HEAD_INITIALIZER(head) \ - { TAILQ_END(head), &(head).tqh_first } - -#define _TAILQ_ENTRY(type, qual) \ -struct { \ - qual type *tqe_next; /* next element */ \ - qual type *qual *tqe_prev; /* address of previous next element */\ -} -#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,) - -/* - * Tail queue access methods. - */ -#define TAILQ_FIRST(head) ((head)->tqh_first) -#define TAILQ_END(head) (NULL) -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) -#define TAILQ_LAST(head, headname) \ - (*(((struct headname *)((head)->tqh_last))->tqh_last)) -#define TAILQ_PREV(elm, headname, field) \ - (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) -#define TAILQ_EMPTY(head) (TAILQ_FIRST(head) == TAILQ_END(head)) - - -#define TAILQ_FOREACH(var, head, field) \ - for ((var) = ((head)->tqh_first); \ - (var) != TAILQ_END(head); \ - (var) = ((var)->field.tqe_next)) - -#define TAILQ_FOREACH_SAFE(var, head, field, next) \ - for ((var) = ((head)->tqh_first); \ - (var) != TAILQ_END(head) && \ - ((next) = TAILQ_NEXT(var, field), 1); (var) = (next)) - -#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ - for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last));\ - (var) != TAILQ_END(head); \ - (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) - -#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, prev) \ - for ((var) = TAILQ_LAST((head), headname); \ - (var) != TAILQ_END(head) && \ - ((prev) = TAILQ_PREV((var), headname, field), 1); (var) = (prev)) - -/* - * Tail queue functions. - */ -#if defined(QUEUEDEBUG) -#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) \ - if ((head)->tqh_first && \ - (head)->tqh_first->field.tqe_prev != &(head)->tqh_first) \ - QUEUEDEBUG_ABORT("TAILQ_INSERT_HEAD %p %s:%d", (head), \ - __FILE__, __LINE__); -#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) \ - if (*(head)->tqh_last != NULL) \ - QUEUEDEBUG_ABORT("TAILQ_INSERT_TAIL %p %s:%d", (head), \ - __FILE__, __LINE__); -#define QUEUEDEBUG_TAILQ_OP(elm, field) \ - if ((elm)->field.tqe_next && \ - (elm)->field.tqe_next->field.tqe_prev != \ - &(elm)->field.tqe_next) \ - QUEUEDEBUG_ABORT("TAILQ_* forw %p %s:%d", (elm), \ - __FILE__, __LINE__); \ - if (*(elm)->field.tqe_prev != (elm)) \ - QUEUEDEBUG_ABORT("TAILQ_* back %p %s:%d", (elm), \ - __FILE__, __LINE__); -#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) \ - if ((elm)->field.tqe_next == NULL && \ - (head)->tqh_last != &(elm)->field.tqe_next) \ - QUEUEDEBUG_ABORT("TAILQ_PREREMOVE head %p elm %p %s:%d",\ - (head), (elm), __FILE__, __LINE__); -#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) \ - (elm)->field.tqe_next = (void *)1L; \ - (elm)->field.tqe_prev = (void *)1L; -#else -#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) -#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) -#define QUEUEDEBUG_TAILQ_OP(elm, field) -#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) -#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) -#endif - -#define TAILQ_INIT(head) do { \ - (head)->tqh_first = TAILQ_END(head); \ - (head)->tqh_last = &(head)->tqh_first; \ -} while (/*CONSTCOND*/0) - -#define TAILQ_INSERT_HEAD(head, elm, field) do { \ - QUEUEDEBUG_TAILQ_INSERT_HEAD((head), (elm), field) \ - if (((elm)->field.tqe_next = (head)->tqh_first) != TAILQ_END(head))\ - (head)->tqh_first->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (head)->tqh_first = (elm); \ - (elm)->field.tqe_prev = &(head)->tqh_first; \ -} while (/*CONSTCOND*/0) - -#define TAILQ_INSERT_TAIL(head, elm, field) do { \ - QUEUEDEBUG_TAILQ_INSERT_TAIL((head), (elm), field) \ - (elm)->field.tqe_next = TAILQ_END(head); \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &(elm)->field.tqe_next; \ -} while (/*CONSTCOND*/0) - -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ - QUEUEDEBUG_TAILQ_OP((listelm), field) \ - if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != \ - TAILQ_END(head)) \ - (elm)->field.tqe_next->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (listelm)->field.tqe_next = (elm); \ - (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ -} while (/*CONSTCOND*/0) - -#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ - QUEUEDEBUG_TAILQ_OP((listelm), field) \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - (elm)->field.tqe_next = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ -} while (/*CONSTCOND*/0) - -#define TAILQ_REMOVE(head, elm, field) do { \ - QUEUEDEBUG_TAILQ_PREREMOVE((head), (elm), field) \ - QUEUEDEBUG_TAILQ_OP((elm), field) \ - if (((elm)->field.tqe_next) != TAILQ_END(head)) \ - (elm)->field.tqe_next->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ - QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \ -} while (/*CONSTCOND*/0) - -#define TAILQ_REPLACE(head, elm, elm2, field) do { \ - if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != \ - TAILQ_END(head)) \ - (elm2)->field.tqe_next->field.tqe_prev = \ - &(elm2)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm2)->field.tqe_next; \ - (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ - *(elm2)->field.tqe_prev = (elm2); \ - QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \ -} while (/*CONSTCOND*/0) - -#define TAILQ_CONCAT(head1, head2, field) do { \ - if (!TAILQ_EMPTY(head2)) { \ - *(head1)->tqh_last = (head2)->tqh_first; \ - (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ - (head1)->tqh_last = (head2)->tqh_last; \ - TAILQ_INIT((head2)); \ - } \ -} while (/*CONSTCOND*/0) - -/* - * Singly-linked Tail queue declarations. - */ -#define STAILQ_HEAD(name, type) \ -struct name { \ - struct type *stqh_first; /* first element */ \ - struct type **stqh_last; /* addr of last next element */ \ -} - -#define STAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).stqh_first } - -#define STAILQ_ENTRY(type) \ -struct { \ - struct type *stqe_next; /* next element */ \ -} - -/* - * Singly-linked Tail queue access methods. - */ -#define STAILQ_FIRST(head) ((head)->stqh_first) -#define STAILQ_END(head) NULL -#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) -#define STAILQ_EMPTY(head) (STAILQ_FIRST(head) == STAILQ_END(head)) - -/* - * Singly-linked Tail queue functions. - */ -#define STAILQ_INIT(head) do { \ - (head)->stqh_first = NULL; \ - (head)->stqh_last = &(head)->stqh_first; \ -} while (/*CONSTCOND*/0) - -#define STAILQ_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ - (head)->stqh_last = &(elm)->field.stqe_next; \ - (head)->stqh_first = (elm); \ -} while (/*CONSTCOND*/0) - -#define STAILQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.stqe_next = NULL; \ - *(head)->stqh_last = (elm); \ - (head)->stqh_last = &(elm)->field.stqe_next; \ -} while (/*CONSTCOND*/0) - -#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ - if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\ - (head)->stqh_last = &(elm)->field.stqe_next; \ - (listelm)->field.stqe_next = (elm); \ -} while (/*CONSTCOND*/0) - -#define STAILQ_REMOVE_HEAD(head, field) do { \ - if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \ - (head)->stqh_last = &(head)->stqh_first; \ -} while (/*CONSTCOND*/0) - -#define STAILQ_REMOVE(head, elm, type, field) do { \ - if ((head)->stqh_first == (elm)) { \ - STAILQ_REMOVE_HEAD((head), field); \ - } else { \ - struct type *curelm = (head)->stqh_first; \ - while (curelm->field.stqe_next != (elm)) \ - curelm = curelm->field.stqe_next; \ - if ((curelm->field.stqe_next = \ - curelm->field.stqe_next->field.stqe_next) == NULL) \ - (head)->stqh_last = &(curelm)->field.stqe_next; \ - } \ -} while (/*CONSTCOND*/0) - -#define STAILQ_FOREACH(var, head, field) \ - for ((var) = ((head)->stqh_first); \ - (var); \ - (var) = ((var)->field.stqe_next)) - -#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = STAILQ_FIRST((head)); \ - (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define STAILQ_CONCAT(head1, head2) do { \ - if (!STAILQ_EMPTY((head2))) { \ - *(head1)->stqh_last = (head2)->stqh_first; \ - (head1)->stqh_last = (head2)->stqh_last; \ - STAILQ_INIT((head2)); \ - } \ -} while (/*CONSTCOND*/0) - -#define STAILQ_LAST(head, type, field) \ - (STAILQ_EMPTY((head)) ? \ - NULL : \ - ((struct type *)(void *) \ - ((char *)((head)->stqh_last) - offsetof(struct type, field)))) - - -#ifndef _KERNEL -/* - * Circular queue definitions. Do not use. We still keep the macros - * for compatibility but because of pointer aliasing issues their use - * is discouraged! - */ - -/* - * __launder_type(): We use this ugly hack to work around the the compiler - * noticing that two types may not alias each other and elide tests in code. - * We hit this in the CIRCLEQ macros when comparing 'struct name *' and - * 'struct type *' (see CIRCLEQ_HEAD()). Modern compilers (such as GCC - * 4.8) declare these comparisons as always false, causing the code to - * not run as designed. - * - * This hack is only to be used for comparisons and thus can be fully const. - * Do not use for assignment. - * - * If we ever choose to change the ABI of the CIRCLEQ macros, we could fix - * this by changing the head/tail sentinal values, but see the note above - * this one. - */ - -#if defined(__GNUC__) && !defined(__CC_ARM) -static __inline const void * __launder_type(const void *); -static __inline const void * -__launder_type(const void *__x) -{ - __asm __volatile("" : "+r" (__x)); - return __x; -} -#else /* defined(__GNUC__) && !defined(__CC_ARM) */ -#define __launder_type(arg) (arg) -#endif /* defined(__GNUC__) && !defined(__CC_ARM) */ - -#if defined(QUEUEDEBUG) -#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field) \ - if ((head)->cqh_first != CIRCLEQ_ENDC(head) && \ - (head)->cqh_first->field.cqe_prev != CIRCLEQ_ENDC(head)) \ - QUEUEDEBUG_ABORT("CIRCLEQ head forw %p %s:%d", (head), \ - __FILE__, __LINE__); \ - if ((head)->cqh_last != CIRCLEQ_ENDC(head) && \ - (head)->cqh_last->field.cqe_next != CIRCLEQ_ENDC(head)) \ - QUEUEDEBUG_ABORT("CIRCLEQ head back %p %s:%d", (head), \ - __FILE__, __LINE__); -#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field) \ - if ((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) { \ - if ((head)->cqh_last != (elm)) \ - QUEUEDEBUG_ABORT("CIRCLEQ elm last %p %s:%d", \ - (elm), __FILE__, __LINE__); \ - } else { \ - if ((elm)->field.cqe_next->field.cqe_prev != (elm)) \ - QUEUEDEBUG_ABORT("CIRCLEQ elm forw %p %s:%d", \ - (elm), __FILE__, __LINE__); \ - } \ - if ((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) { \ - if ((head)->cqh_first != (elm)) \ - QUEUEDEBUG_ABORT("CIRCLEQ elm first %p %s:%d", \ - (elm), __FILE__, __LINE__); \ - } else { \ - if ((elm)->field.cqe_prev->field.cqe_next != (elm)) \ - QUEUEDEBUG_ABORT("CIRCLEQ elm prev %p %s:%d", \ - (elm), __FILE__, __LINE__); \ - } -#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field) \ - (elm)->field.cqe_next = (void *)1L; \ - (elm)->field.cqe_prev = (void *)1L; -#else -#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field) -#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field) -#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field) -#endif - -#define CIRCLEQ_HEAD(name, type) \ -struct name { \ - struct type *cqh_first; /* first element */ \ - struct type *cqh_last; /* last element */ \ -} - -#define CIRCLEQ_HEAD_INITIALIZER(head) \ - { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } - -#define CIRCLEQ_ENTRY(type) \ -struct { \ - struct type *cqe_next; /* next element */ \ - struct type *cqe_prev; /* previous element */ \ -} - -/* - * Circular queue functions. - */ -#define CIRCLEQ_INIT(head) do { \ - (head)->cqh_first = CIRCLEQ_END(head); \ - (head)->cqh_last = CIRCLEQ_END(head); \ -} while (/*CONSTCOND*/0) - -#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ - QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ - QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \ - (elm)->field.cqe_next = (listelm)->field.cqe_next; \ - (elm)->field.cqe_prev = (listelm); \ - if ((listelm)->field.cqe_next == CIRCLEQ_ENDC(head)) \ - (head)->cqh_last = (elm); \ - else \ - (listelm)->field.cqe_next->field.cqe_prev = (elm); \ - (listelm)->field.cqe_next = (elm); \ -} while (/*CONSTCOND*/0) - -#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ - QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ - QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \ - (elm)->field.cqe_next = (listelm); \ - (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ - if ((listelm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \ - (head)->cqh_first = (elm); \ - else \ - (listelm)->field.cqe_prev->field.cqe_next = (elm); \ - (listelm)->field.cqe_prev = (elm); \ -} while (/*CONSTCOND*/0) - -#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ - QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ - (elm)->field.cqe_next = (head)->cqh_first; \ - (elm)->field.cqe_prev = CIRCLEQ_END(head); \ - if ((head)->cqh_last == CIRCLEQ_ENDC(head)) \ - (head)->cqh_last = (elm); \ - else \ - (head)->cqh_first->field.cqe_prev = (elm); \ - (head)->cqh_first = (elm); \ -} while (/*CONSTCOND*/0) - -#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ - QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ - (elm)->field.cqe_next = CIRCLEQ_END(head); \ - (elm)->field.cqe_prev = (head)->cqh_last; \ - if ((head)->cqh_first == CIRCLEQ_ENDC(head)) \ - (head)->cqh_first = (elm); \ - else \ - (head)->cqh_last->field.cqe_next = (elm); \ - (head)->cqh_last = (elm); \ -} while (/*CONSTCOND*/0) - -#define CIRCLEQ_REMOVE(head, elm, field) do { \ - QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ - QUEUEDEBUG_CIRCLEQ_ELM((head), (elm), field) \ - if ((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) \ - (head)->cqh_last = (elm)->field.cqe_prev; \ - else \ - (elm)->field.cqe_next->field.cqe_prev = \ - (elm)->field.cqe_prev; \ - if ((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \ - (head)->cqh_first = (elm)->field.cqe_next; \ - else \ - (elm)->field.cqe_prev->field.cqe_next = \ - (elm)->field.cqe_next; \ - QUEUEDEBUG_CIRCLEQ_POSTREMOVE((elm), field) \ -} while (/*CONSTCOND*/0) - -#define CIRCLEQ_FOREACH(var, head, field) \ - for ((var) = ((head)->cqh_first); \ - (var) != CIRCLEQ_ENDC(head); \ - (var) = ((var)->field.cqe_next)) - -#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ - for ((var) = ((head)->cqh_last); \ - (var) != CIRCLEQ_ENDC(head); \ - (var) = ((var)->field.cqe_prev)) - -/* - * Circular queue access methods. - */ -#define CIRCLEQ_FIRST(head) ((head)->cqh_first) -#define CIRCLEQ_LAST(head) ((head)->cqh_last) -/* For comparisons */ -#define CIRCLEQ_ENDC(head) (__launder_type(head)) -/* For assignments */ -#define CIRCLEQ_END(head) ((void *)(head)) -#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) -#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) -#define CIRCLEQ_EMPTY(head) \ - (CIRCLEQ_FIRST(head) == CIRCLEQ_ENDC(head)) - -#define CIRCLEQ_LOOP_NEXT(head, elm, field) \ - (((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) \ - ? ((head)->cqh_first) \ - : (elm->field.cqe_next)) -#define CIRCLEQ_LOOP_PREV(head, elm, field) \ - (((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \ - ? ((head)->cqh_last) \ - : (elm->field.cqe_prev)) -#endif /* !_KERNEL */ - -#endif /* !_SYS_QUEUE_H_ */ diff --git a/sdk/modules/bluetooth/hal/bcm20706/manager/bt_recv_task.c b/sdk/modules/bluetooth/hal/bcm20706/manager/bt_recv_task.c index c6281092e..0ee93536b 100644 --- a/sdk/modules/bluetooth/hal/bcm20706/manager/bt_recv_task.c +++ b/sdk/modules/bluetooth/hal/bcm20706/manager/bt_recv_task.c @@ -1,7 +1,7 @@ /**************************************************************************** * modules/bluetooth/hal/bcm20706/manager/bt_recv_task.c * - * Copyright 2018 Sony Semiconductor Solutions Corporation + * Copyright 2018, 2024 Sony Semiconductor Solutions Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -709,36 +709,19 @@ void bleRecvLeAdverReport(BLE_Evt *pBleEvent, ble_evt_t *pBleBcmEvt, uint16_t le rp += BLE_GAP_ADDR_LENGTH; STREAM_TO_UINT8(adv_rept_evt.rssi, rp); - adv_rept_evt.length = len - BLE_GAP_ADDR_LENGTH - BLE_HANDLE_LEN - BLE_ADV_RSSI_LEN; - memcpy(adv_rept_evt.data, rp, BLE_GAP_ADV_MAX_SIZE); + /* The first octet is used for notification of peer address type. */ -#ifndef REPORT_ALL_ADV_DATA /* report device name only */ - uint32_t idx = 0; - uint8_t field_len = 0; - uint8_t field_type = 0; - uint8_t adv_data[BLE_GAP_ADV_MAX_SIZE] = {0}; + adv_rept_evt.data[0] = pBleBcmEvt->evtData[1]; - memcpy(adv_data, adv_rept_evt.data, adv_rept_evt.length); + /* The second octet is used for notification of rssi. */ - while (idx < adv_rept_evt.length) - { - field_len = adv_data[idx]; - field_type = adv_data[idx + 1]; - - if (0x09 == field_type) { /* 0x09: Complete local name */ - adv_rept_evt.length = field_len; - memset(adv_rept_evt.data, 0, sizeof(adv_rept_evt.data)); - memcpy(adv_rept_evt.data, &adv_data[idx + 2], field_len - 1); - ble_common_event_handler((struct bt_event_t *) &adv_rept_evt); - return; - } - idx += field_len + 1; - } -#else - ble_common_event_handler((struct bt_event_t *) &adv_rept_evt); -#endif /* REPORT_ALL_ADV_DATA */ + adv_rept_evt.data[1] = (uint8_t)adv_rept_evt.rssi; + len = len - BLE_GAP_ADDR_LENGTH - BLE_HANDLE_LEN - BLE_ADV_RSSI_LEN; + memcpy(&adv_rept_evt.data[2], rp, len); + adv_rept_evt.length = len + 2; + ble_common_event_handler((struct bt_event_t *) &adv_rept_evt); } void bleRecvGattReadRequest(BLE_Evt *pBleEvent, ble_evt_t *pBleBcmEvt) diff --git a/sdk/modules/bluetooth/hal/bcm20706/manager/bt_storage_manager.c b/sdk/modules/bluetooth/hal/bcm20706/manager/bt_storage_manager.c index 735623732..7dd046e03 100644 --- a/sdk/modules/bluetooth/hal/bcm20706/manager/bt_storage_manager.c +++ b/sdk/modules/bluetooth/hal/bcm20706/manager/bt_storage_manager.c @@ -1,7 +1,7 @@ /**************************************************************************** * modules/bluetooth/hal/bcm20706/manager/bt_storage_manager.c * - * Copyright 2018 Sony Semiconductor Solutions Corporation + * Copyright 2018, 2024 Sony Semiconductor Solutions Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -46,8 +46,8 @@ #include #include #include +#include -#include "queue.h" /* TODO: replace to nuttx/include/queue.h */ #include "manager/bt_storage_manager.h" #include "bt_debug.h" diff --git a/sdk/modules/bluetooth/hal/nrf52/Kconfig b/sdk/modules/bluetooth/hal/nrf52/Kconfig index 15560c1d8..44008684a 100644 --- a/sdk/modules/bluetooth/hal/nrf52/Kconfig +++ b/sdk/modules/bluetooth/hal/nrf52/Kconfig @@ -32,6 +32,15 @@ config NRF52_LESC This option enables LE secure connection feature of nRF52. LE secure connection is the safer pairing method, but nrf52 needs more memory because mbedtls or micro-ecc is required. + +config NRF52_SCAN_COMPAT_MODE + bool "Enable scan compatible mode" + default n + ---help--- + Enable interoperability with devices that do not support a value of + 0 for the WinOffset parameter in the Link Layer CONNECT_IND packet. + This applies to a limited set of legacy peripheral devices. + endif # NRF52_LE endif # BLUETOOTH_NRF52 diff --git a/sdk/modules/bluetooth/hal/nrf52/Make.defs b/sdk/modules/bluetooth/hal/nrf52/Make.defs index 58e8734e6..5cd0c5874 100644 --- a/sdk/modules/bluetooth/hal/nrf52/Make.defs +++ b/sdk/modules/bluetooth/hal/nrf52/Make.defs @@ -42,7 +42,7 @@ BLE_API_VERSION := 7 endif # SOURCES -BLE_C_FILES := $(shell find $(BLEDIR) -name "*.c" -printf '%f ') +BLE_C_FILES := $(notdir $(shell find $(BLEDIR) -name "*.c")) BLE_C_DIRS := $(sort $(dir $(shell find $(BLEDIR) -name "*.c"))) # INCLUDES BLE_H_DIRS := $(sort $(dir $(shell find $(BLEDIR) -name "*.h" -not -path $(BLE_IGNORE_DIR)))) diff --git a/sdk/modules/bluetooth/hal/nrf52/ble_comm.c b/sdk/modules/bluetooth/hal/nrf52/ble_comm.c index 4a9a02e71..59bcca6bd 100644 --- a/sdk/modules/bluetooth/hal/nrf52/ble_comm.c +++ b/sdk/modules/bluetooth/hal/nrf52/ble_comm.c @@ -1,7 +1,7 @@ /**************************************************************************** * modules/bluetooth/hal/nrf52/ble_comm.c * - * Copyright 2022 Sony Semiconductor Solutions Corporation + * Copyright 2022, 2024 Sony Semiconductor Solutions Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -56,6 +56,7 @@ #include #include #include +#include /****************************************************************************** * externs @@ -63,7 +64,6 @@ extern bleGapMem *bleGetGapMem(void); extern void bleMngEvtDispatch(ble_evt_t *nrfEvt); extern void board_nrf52_initialize(void); -extern void board_nrf52_reset(bool en); /**************************************************************************** * Pre-processor Definitions @@ -77,6 +77,9 @@ extern void board_nrf52_reset(bool en); #define NRF52_SYS_ATTR_DATA_LEN_LEN (2) #define NRF52_SYS_ATTR_DATA_LEN_VALUE (2) +#define IM_ADDR_CLEARTEXT_LENGTH (3) +#define IM_ADDR_CIPHERTEXT_LENGTH (3) + /****************************************************************************** * Structure define *****************************************************************************/ @@ -138,7 +141,7 @@ static int nrf52_ble_stop_scan(void); static int nrf52_ble_connect(uint8_t addr_type, const BT_ADDR *addr); static int nrf52_ble_disconnect(const uint16_t conn_handle); static int nrf52_ble_advertise(bool enable); -static int nrf52_ble_set_dev_addr(BT_ADDR *addr); +static int nrf52_ble_set_dev_addr(BT_ADDR *addr, uint8_t type); static int nrf52_ble_set_dev_name(char *name); static int nrf52_ble_set_appearance(BLE_APPEARANCE appearance); static int nrf52_ble_set_ppcp(BLE_CONN_PARAMS ppcp); @@ -146,6 +149,9 @@ static uint16_t nrf52_ble_set_mtusize(uint16_t sz); static uint16_t nrf52_ble_get_mtusize(void); static int nrf52_ble_get_negotiated_mtusize(uint16_t handle); static int nrf52_ble_pairing(uint16_t handle); +static int nrf52_ble_set_txpower(int8_t tx_power); +static int nrf52_ble_set_scan_param(struct ble_scan_param_s *param); +static int nrf52_ble_set_conn_param(struct ble_conn_param_s *param); static int nrf52_bt_init(void); static int nrf52_bt_finalize(void); @@ -186,6 +192,9 @@ static struct ble_hal_common_ops_s ble_hal_common_ops = .getMtuSize = nrf52_ble_get_mtusize, .getNegotiatedMtuSize = nrf52_ble_get_negotiated_mtusize, .pairing = nrf52_ble_pairing, + .setTxPower = nrf52_ble_set_txpower, + .setScanParam = nrf52_ble_set_scan_param, + .setConnParam = nrf52_ble_set_conn_param, }; static struct bt_hal_common_ops_s bt_hal_common_ops = @@ -213,9 +222,12 @@ static int blePowerOff(void) { int ret = 0; -// for support reset pin. (Will be valid later) -// board_nrf52_reset(true); - ret = board_power_control(POWER_BTBLE, false); + /* Control the reset pin instead of the power. + * true (HIGH) : reset assert + * false (LOW) : reset deassert + */ + + ret = board_power_control(POWER_BTBLE, true); if (ret) { BLE_PRT("board_power_control(off): NG %d\n", ret); @@ -260,8 +272,8 @@ static void set_bondinfo_for_save_event(struct ble_bondinfo_s *apps, nrf52->bondInfo.addr, BLE_GAP_ADDR_LENGTH); - memcpy(nrf52->ownIdKey.id_info.irk, apps->own.irk, BLE_GAP_SEC_KEY_LEN); - memcpy(nrf52->peerIdKey.id_info.irk, apps->peer.irk, BLE_GAP_SEC_KEY_LEN); + memcpy(apps->own.irk, nrf52->ownIdKey.id_info.irk, BLE_GAP_SEC_KEY_LEN); + memcpy(apps->peer.irk, nrf52->peerIdKey.id_info.irk, BLE_GAP_SEC_KEY_LEN); set_EncKey_for_save_event(&apps->own, &nrf52->ownEncKey); set_EncKey_for_save_event(&apps->peer, &nrf52->peerEncKey); @@ -509,18 +521,24 @@ static int blePowerOn(void) { int ret = 0; - ret = board_power_control(POWER_BTBLE, true); + + /* Control the reset pin instead of the power. + * true (HIGH) : reset assert + * false (LOW) : reset deassert + */ + + ret = board_power_control(POWER_BTBLE, false); + if (ret) { BLE_PRT("board_power_control(on): NG %d\n", ret); goto errPower; } -// for support reset pin. (Will be valid later) -// board_nrf52_reset(false); + BLE_PRT("Power on BLE!!\n"); return BLE_SUCCESS; errPower: - (void)board_power_control(POWER_BTBLE, false); + (void)board_power_control(POWER_BTBLE, true); return ret; } @@ -849,6 +867,7 @@ static void on_connected(const BLE_EvtConnected* evt) g_ble_context.conn_sts = BLE_CONN_STS_CONNECTED; g_ble_context.is_scanning = false; g_ble_context.is_advertising = false; + g_ble_context.ble_addr.type = evt->addr.type; memcpy(g_ble_context.ble_addr.addr, evt->addr.addr, BT_ADDR_LEN); conn_stat_evt.connected = true; @@ -1182,15 +1201,19 @@ static void on_adv_report(BLE_EvtAdvReportData *adv_report) evt.event_id = BLE_COMMON_EVENT_SCAN_RESULT; evt.rssi = adv_report->rssi; evt.scan_rsp = adv_report->scan_rsp; - evt.length = adv_report->dlen + 1; + evt.length = adv_report->dlen + 2; /* The first octet is used for notification of peer address type. */ evt.data[0] = adv_report->addr.type; - /* The raw advertising data starts from second octet. */ + /* The second octet is used for notification of rssi. */ + + evt.data[1] = (uint8_t)adv_report->rssi; - memcpy(evt.data + 1, adv_report->data, adv_report->dlen); + /* The raw advertising data starts from the third octet. */ + + memcpy(&evt.data[2], adv_report->data, adv_report->dlen); memcpy(evt.addr.address, adv_report->addr.addr, BLE_GAP_ADDR_LENGTH); ble_common_event_handler((struct bt_event_t *)&evt); } @@ -1413,22 +1436,74 @@ void onTxComplete(BLE_Evt *pBleEvent, ble_evt_t *pBleNrfEvt) memcpy(pBleEvent->evtData, &commMem.txCompleteData, pBleEvent->evtDataSize); } -static int searchBondInfoIndex(ble_gap_master_id_t *id) +/* Calculate the ah() hash function described in Bluetooth core specification */ + +static void ah(uint8_t const *p_k, uint8_t const *p_r, uint8_t *p_local_hash) { - int i; + nrf_ecb_hal_data_t ecb_hal_data; + uint32_t i; + + for (i = 0; i < SOC_ECB_KEY_LENGTH; i++) + { + ecb_hal_data.key[i] = p_k[SOC_ECB_KEY_LENGTH - 1 - i]; + } + + memset(ecb_hal_data.cleartext, 0, SOC_ECB_KEY_LENGTH - IM_ADDR_CLEARTEXT_LENGTH); + + for (i = 0; i < IM_ADDR_CLEARTEXT_LENGTH; i++) + { + ecb_hal_data.cleartext[SOC_ECB_KEY_LENGTH - 1 - i] = p_r[i]; + } + + sd_ecb_block_encrypt(&ecb_hal_data); + + for (i = 0; i < IM_ADDR_CIPHERTEXT_LENGTH; i++) + { + p_local_hash[i] = ecb_hal_data.ciphertext[SOC_ECB_KEY_LENGTH - 1 - i]; + } +} + +static bool im_address_resolve(ble_gap_addr_t const *p_addr, ble_gap_irk_t const *p_irk) +{ + uint8_t hash[IM_ADDR_CIPHERTEXT_LENGTH]; + uint8_t local_hash[IM_ADDR_CIPHERTEXT_LENGTH]; + uint8_t prand[IM_ADDR_CLEARTEXT_LENGTH]; + if (p_addr->addr_type != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE) + { + return false; + } + + memcpy(hash, p_addr->addr, IM_ADDR_CIPHERTEXT_LENGTH); + memcpy(prand, &p_addr->addr[IM_ADDR_CIPHERTEXT_LENGTH], IM_ADDR_CLEARTEXT_LENGTH); + ah(p_irk->irk, prand, local_hash); + + return (memcmp(hash, local_hash, IM_ADDR_CIPHERTEXT_LENGTH) == 0); +} + +static int searchBondInfoIndexAddress(ble_gap_addr_t *addr) +{ + int i; uint32_t list = bleBondEnableList; for (i = 0; i < BLE_SAVE_BOND_DEVICE_MAX_NUM; i++, list >>= 1) { if (list & 1) { - if (memcmp(&BondInfoInFlash[i].ownEncKey.master_id, - id, - sizeof(ble_gap_master_id_t)) - == 0) + if ((addr->addr_type == BLE_GAP_ADDR_TYPE_PUBLIC) || + (addr->addr_type == BLE_GAP_ADDR_TYPE_RANDOM_STATIC)) { - break; + if (memcmp(BondInfoInFlash[i].bondInfo.addr, addr->addr, BLE_GAP_ADDR_LEN) == 0) + { + break; + } + } + else if (addr->addr_type == BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE) + { + if (im_address_resolve(addr, &BondInfoInFlash[i].peerIdKey.id_info)) + { + break; + } } } } @@ -1514,8 +1589,11 @@ static void saveSysAttrData(ble_gap_master_id_t *id, uint8_t *sys_attr_data) { int index; + ble_gap_addr_t addr; - index = searchBondInfoIndex(id); + addr.addr_type = g_ble_context.ble_addr.type; + memcpy(addr.addr, g_ble_context.ble_addr.addr, BLE_GAP_ADDR_LENGTH); + index = searchBondInfoIndexAddress(&addr); if (index < BLE_SAVE_BOND_DEVICE_MAX_NUM) { @@ -2000,7 +2078,7 @@ void onSecInfoRequest(BLE_Evt *pBleEvent, ble_evt_t *pBleNrfEvt) BLE_PRT("onSecInfoRequest: peer enc_info_ltk=%d\n", commMem.gapMem->wrapperBondInfo.peerEncKey.enc_info.ltk_len); } - index = searchBondInfoIndex(&secinfo->master_id); + index = searchBondInfoIndexAddress(&secinfo->peer_addr); if (index < BLE_SAVE_BOND_DEVICE_MAX_NUM) { @@ -2302,17 +2380,25 @@ void setDbDiscoveryEvent(BLE_Evt *pBleEvent, uint16_t connHandle, int result, in * Then, the last handle value should be notified. */ - last_srv = &evt.params.db_discovery.services[evt.params.db_discovery.srv_count - 1]; - last_chrc = &last_srv->characteristics[last_srv->char_count - 1]; - - if (last_srv->char_count >= BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV) + if (evt.params.db_discovery.srv_count == 0) { - evt.state.end_handle = get_last_handle(last_chrc); + evt.state.end_handle = 0; + commMem.disc.start = 0; } else { - evt.state.end_handle = last_srv->srv_handle_range.end_handle; - commMem.disc.start = 0; + last_srv = &evt.params.db_discovery.services[evt.params.db_discovery.srv_count - 1]; + last_chrc = &last_srv->characteristics[last_srv->char_count - 1]; + + if (last_srv->char_count >= BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV) + { + evt.state.end_handle = get_last_handle(last_chrc); + } + else + { + evt.state.end_handle = last_srv->srv_handle_range.end_handle; + commMem.disc.start = 0; + } } ble_gatt_event_handler((struct bt_event_t *)&evt); @@ -2817,7 +2903,7 @@ void onSrvDiscCompletion(BLE_Evt *pBleEvent, bleGattcDb *gattcDbDiscovery) srvBeingDiscovered = &(gattcDbDiscovery->dbDiscovery.services[gattcDbDiscovery->currSrvInd]); srvBeingDiscovered->charCount = 0; - /* Discover characterisitics of next service. */ + /* Discover characteristics of next service. */ (void)characteristicsDiscover(pBleEvent, gattcDbDiscovery); } @@ -3018,7 +3104,7 @@ int descriptorsDiscover(BLE_Evt *pBleEvent, bleGattcDb *const gattcDbDiscovery, if (!isDiscoveryReqd) { // No more descriptor discovery required. - // Preceed to the characteristics discovery about next service. + // Proceed to the characteristics discovery about next service. gattcDbDiscovery->currSrvInd++; gattcDbDiscovery->currCharInd = 0; @@ -3058,9 +3144,8 @@ int descriptorsDiscover(BLE_Evt *pBleEvent, bleGattcDb *const gattcDbDiscovery, static int32_t set_adv_data(void) { -#define BLE_TX_POWER_LEVEL 0 int ret = 0; - int8_t tx_power = BLE_TX_POWER_LEVEL; + int8_t tx_power = commMem.gapMem->txPower; BLE_GapAdvData adv_data = {0}; adv_data.flags = BLE_GAP_ADV_LE_GENERAL_DISC_MODE | BLE_GAP_ADV_BR_EDR_NOT_SUPPORTED; @@ -3273,12 +3358,12 @@ static int nrf52_ble_advertise(bool enable) return ret; } -static int nrf52_ble_set_dev_addr(BT_ADDR *addr) +static int nrf52_ble_set_dev_addr(BT_ADDR *addr, uint8_t type) { int ret; ble_gap_addr_t nrf52_addr; - nrf52_addr.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_STATIC; + nrf52_addr.addr_type = type; memcpy(nrf52_addr.addr, addr->address, sizeof(nrf52_addr.addr)); ret = sd_ble_gap_addr_set(&nrf52_addr); @@ -3294,7 +3379,7 @@ static int nrf52_ble_set_dev_name(char *name) nameSize = strlen(name); - /* If invalid size, retrun NG */ + /* If invalid size, return error */ if (!name || nameSize > BT_MAX_NAME_LEN) { @@ -3312,8 +3397,10 @@ static int nrf52_ble_set_dev_name(char *name) static int nrf52_ble_set_appearance(BLE_APPEARANCE appearance) { - int ret = BT_SUCCESS; - return ret; + uint32_t errCode; + + errCode = sd_ble_gap_appearance_set((uint16_t)appearance); + return bleConvertErrorCode(errCode); } static int nrf52_ble_set_ppcp(BLE_CONN_PARAMS ppcp) @@ -3372,7 +3459,18 @@ static int nrf52_ble_pairing(uint16_t handle) * skip pairing and only encrypt with stored key. */ - ret = BLE_GapEncrypt(handle, &BondInfoInFlash[ret].peerEncKey); + if (BondInfoInFlash[ret].ownEncKey.master_id.ediv != 0) + { + /* LE Legacy Pairing */ + + ret = BLE_GapEncrypt(handle, &BondInfoInFlash[ret].peerEncKey); + } + else + { + /* LE Secure Connections Pairing */ + + ret = BLE_GapEncrypt(handle, &BondInfoInFlash[ret].ownEncKey); + } } else { @@ -3384,6 +3482,74 @@ static int nrf52_ble_pairing(uint16_t handle) return ret; } +/**************************************************************************** + * Name: nrf52_ble_set_txpower + * + * Description: + * Bluetooth LE set Tx Power + * Supported tx_power values: + * -40, -20, -16, -12, -8, -4, 0, +3 and +4 [dBm] + * + ****************************************************************************/ + +static int nrf52_ble_set_txpower(int8_t tx_power) +{ + int ret = 0; + + if (!commMem.gapMem) + { + LOG_OUT("Must be called after BLE is enabled.\n"); + return -EPERM; + } + + switch (tx_power) + { + case -40: + case -20: + case -16: + case -12: + case -8: + case -4: + case 0: + case 3: + case 4: + commMem.gapMem->txPower = tx_power; + break; + default: + commMem.gapMem->txPower = 0; /* set default if illegal value */ + ret = -EINVAL; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: nrf52_ble_set_scan_param + * + * Description: + * Bluetooth LE set scan parameter + * + ****************************************************************************/ + +static int nrf52_ble_set_scan_param(struct ble_scan_param_s *param) +{ + return BLE_GapSetScanParam(param); +} + +/**************************************************************************** + * Name: nrf52_ble_set_conn_param + * + * Description: + * Bluetooth LE set connection parameter + * + ****************************************************************************/ + +static int nrf52_ble_set_conn_param(struct ble_conn_param_s *param) +{ + return BLE_GapSetConnectionParams((BLE_GapConnParams *)param); +} + /**************************************************************************** * Public Data ****************************************************************************/ diff --git a/sdk/modules/bluetooth/hal/nrf52/ble_comm_internal.h b/sdk/modules/bluetooth/hal/nrf52/ble_comm_internal.h index 8ce995b76..2b2d65758 100644 --- a/sdk/modules/bluetooth/hal/nrf52/ble_comm_internal.h +++ b/sdk/modules/bluetooth/hal/nrf52/ble_comm_internal.h @@ -126,6 +126,7 @@ typedef struct uint8_t is_connected; int8_t peerRssi; uint8_t startRssi; + int8_t txPower; } bleGapMem; typedef struct diff --git a/sdk/modules/bluetooth/hal/nrf52/ble_gap.c b/sdk/modules/bluetooth/hal/nrf52/ble_gap.c index 15aff003f..3102459bb 100644 --- a/sdk/modules/bluetooth/hal/nrf52/ble_gap.c +++ b/sdk/modules/bluetooth/hal/nrf52/ble_gap.c @@ -108,6 +108,10 @@ extern int bleConvertErrorCode(uint32_t errCode); #define MIN_SCAN_TIMEOUT 0x0000 #define MAX_SCAN_TIMEOUT 0xFFFF +#define IS_INVALID_SCAN_PARAM(interval, window) \ + (((interval) < BLE_GAP_SCAN_INTERVAL_MIN) || \ + ((window) < BLE_GAP_SCAN_WINDOW_MIN)) + #define MIN_CONNECTION_INTERVAL MSEC_TO_UNITS(7.5, UNIT_1_25_MS) #define MAX_CONNECTION_INTERVAL MSEC_TO_UNITS(30, UNIT_1_25_MS) #define SLAVE_LATENCY 0 @@ -120,6 +124,15 @@ extern int bleConvertErrorCode(uint32_t errCode); #define CONNECTION_TIMEOUT 1000 +#define IS_INVALID_CONN_PARAM(min, max, slave, timeout) \ + (((min) < BLE_GAP_CP_MIN_CONN_INTVL_MIN) || \ + ((min) > BLE_GAP_CP_MIN_CONN_INTVL_MAX) || \ + ((max) < BLE_GAP_CP_MAX_CONN_INTVL_MIN) || \ + ((max) > BLE_GAP_CP_MAX_CONN_INTVL_MAX) || \ + ((slave) > BLE_GAP_CP_SLAVE_LATENCY_MAX) || \ + ((timeout) < BLE_GAP_CP_CONN_SUP_TIMEOUT_MIN)|| \ + ((timeout) > BLE_GAP_CP_CONN_SUP_TIMEOUT_MAX)) + /* Flash handle key name size */ #define FLASH_KEY_NAME_SIZE 4 #define FLASH_KEY_NAME_2 2 @@ -550,7 +563,7 @@ int BLE_GapExchangePairingFeature(BLE_GapConnHandle connHandle, } BLE_PRT("\n"); } else { - BLE_PRT("ExchangePairing: peer enc_info_ltk=%d\n", gapMem.wrapperBondInfo.peerEncKey.enc_info.ltk_len); + BLE_PRT("ExchangePairing: own enc_info_ltk=%d\n", gapMem.wrapperBondInfo.ownEncKey.enc_info.ltk_len); } // peer @@ -590,38 +603,36 @@ static int8_t ble_gap_scan_tx_power = 0; uint8_t bleAdvReportBuffer[BLE_GAP_SCAN_BUFFER_EXTENDED_MIN]; #endif -int BLE_GapSetScanParam(BLE_GapScanParams *scanParam) +int BLE_GapSetScanCompatMode(bool enable) +{ + int ret = BLE_SUCCESS; + int errCode = 0; + ble_opt_t opt; + + memset(&opt, 0x0, sizeof(opt)); + opt.gap_opt.compat_mode_1.enable = enable ? 1 : 0; + + errCode = sd_ble_opt_set(BLE_GAP_OPT_COMPAT_MODE_1, &opt); + ret = bleConvertErrorCode((uint32_t)errCode); + + return ret; +} + +int BLE_GapSetScanParam(struct ble_scan_param_s *scanParam) { if(scanParam == NULL) { return -EINVAL; } - if (!(scanParam->interval > MAX_SCAN_INTERVAL || - scanParam->interval < MIN_SCAN_INTERVAL || - scanParam->window > MAX_SCAN_WINDOW || - scanParam->window < MIN_SCAN_WINDOW || - scanParam->timeout > MAX_SCAN_TIMEOUT || - scanParam->timeout < MIN_SCAN_TIMEOUT)) { - gapMem.scanParams.active = scanParam->active; - //gapMem.scanParams.selective = 0; - gapMem.scanParams.interval = scanParam->interval; - gapMem.scanParams.window = scanParam->window; - //gapMem.scanParams.p_whitelist = NULL; - gapMem.scanParams.timeout = scanParam->timeout; - } - else { + if (IS_INVALID_SCAN_PARAM(scanParam->interval, + scanParam->window)) { return -EINVAL; } -#if NRF_SD_BLE_API_VERSION > 5 - gapMem.scanParams.filter_policy = BLE_GAP_SCAN_FP_ACCEPT_ALL; - gapMem.scanParams.scan_phys = scanParam->scan_phys; - if (gapMem.scanParams.scan_phys == BLE_GAP_PHY_CODED) { - gapMem.scanParams.extended = 1; - } - else { - gapMem.scanParams.extended = 0; - } - ble_gap_scan_tx_power = scanParam->tx_power; -#endif + + gapMem.scanParams.active = scanParam->active; + gapMem.scanParams.interval = scanParam->interval; + gapMem.scanParams.window = scanParam->window; + gapMem.scanParams.timeout = scanParam->timeout; + return 0; } @@ -630,25 +641,32 @@ int BLE_GapStartScan(void) int ret = BLE_SUCCESS; int errCode = 0; - if ((gapMem.scanParams.interval > MAX_SCAN_INTERVAL || - gapMem.scanParams.interval < MIN_SCAN_INTERVAL || - gapMem.scanParams.window > MAX_SCAN_WINDOW || - gapMem.scanParams.window < MIN_SCAN_WINDOW || - gapMem.scanParams.timeout > MAX_SCAN_TIMEOUT || - gapMem.scanParams.timeout < MIN_SCAN_TIMEOUT)) { - // default - gapMem.scanParams.active = EXECUTE_ACTIVE_SCAN; - gapMem.scanParams.interval = SCAN_INTERVAL; - gapMem.scanParams.window = SCAN_WINDOW; - gapMem.scanParams.timeout = SCAN_TIMEOUT; -#if NRF_SD_BLE_API_VERSION > 5 - gapMem.scanParams.filter_policy = BLE_GAP_SCAN_FP_ACCEPT_ALL; - gapMem.scanParams.scan_phys = BLE_GAP_PHY_1MBPS; - gapMem.scanParams.extended = ENABLE_EXTENDED_ADV_RECV; - ble_gap_scan_tx_power = 0; -#endif + if (IS_INVALID_SCAN_PARAM(gapMem.scanParams.interval, + gapMem.scanParams.window)) { + /* If scan parameter is not set, use the default value. */ + + gapMem.scanParams.active = EXECUTE_ACTIVE_SCAN; + gapMem.scanParams.interval = SCAN_INTERVAL; + gapMem.scanParams.window = SCAN_WINDOW; + gapMem.scanParams.timeout = SCAN_TIMEOUT; } + +#ifdef CONFIG_NRF52_SCAN_COMPAT_MODE + /* Allow connection to legacy peripheral device that do not support + * a Window offset parameter of 0. + */ + + BLE_GapSetScanCompatMode(true); +#endif + #if NRF_SD_BLE_API_VERSION > 5 + /* Always use the fixed value. */ + + gapMem.scanParams.filter_policy = BLE_GAP_SCAN_FP_ACCEPT_ALL; + gapMem.scanParams.scan_phys = BLE_GAP_PHY_1MBPS; + gapMem.scanParams.extended = ENABLE_EXTENDED_ADV_RECV; + + ble_gap_scan_tx_power = gapMem.txPower; errCode = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_SCAN_INIT, 0, ble_gap_scan_tx_power); if (errCode) { @@ -721,11 +739,35 @@ int BLE_GapStopScan(void) return ret; } +int BLE_GapSetConnectionParams(BLE_GapConnParams *connParams) +{ + int ret = BLE_SUCCESS; + + if (connParams == NULL) { + return -EINVAL; + } + + if (IS_INVALID_CONN_PARAM(connParams->minConnInterval, + connParams->maxConnInterval, + connParams->slaveLatency, + connParams->connSupTimeout)) { + return -EINVAL; + } + + gapMem.connParams.min_conn_interval = connParams->minConnInterval; + gapMem.connParams.max_conn_interval = connParams->maxConnInterval; + gapMem.connParams.slave_latency = connParams->slaveLatency; + gapMem.connParams.conn_sup_timeout = connParams->connSupTimeout; + + return ret; +} + int BLE_GapConnect(BLE_GapAddr *addr) { int ret = BLE_SUCCESS; int errCode = 0; ble_gap_addr_t peerAddr = {0}; + ble_gap_scan_params_t scanParams; if(addr == NULL) { return -EINVAL; @@ -740,16 +782,25 @@ int BLE_GapConnect(BLE_GapAddr *addr) * application wait connection infinitely. */ - gapMem.scanParams.timeout = CONNECTION_TIMEOUT; + memcpy(&scanParams, &gapMem.scanParams, sizeof(scanParams)); + scanParams.timeout = CONNECTION_TIMEOUT; + + if (IS_INVALID_CONN_PARAM(gapMem.connParams.min_conn_interval, + gapMem.connParams.max_conn_interval, + gapMem.connParams.slave_latency, + gapMem.connParams.conn_sup_timeout)) { + /* If connection parameter is not set, use the default value. */ + + gapMem.connParams.min_conn_interval = MIN_CONNECTION_INTERVAL; + gapMem.connParams.max_conn_interval = MAX_CONNECTION_INTERVAL; + gapMem.connParams.slave_latency = SLAVE_LATENCY; + gapMem.connParams.conn_sup_timeout = SUPERVISION_TIMEOUT; + } - gapMem.connParams.min_conn_interval = MIN_CONNECTION_INTERVAL; - gapMem.connParams.max_conn_interval = MAX_CONNECTION_INTERVAL; - gapMem.connParams.slave_latency = SLAVE_LATENCY; - gapMem.connParams.conn_sup_timeout = SUPERVISION_TIMEOUT; peerAddr.addr_type = addr->type; memcpy(peerAddr.addr, addr->addr, BLE_GAP_ADDR_LENGTH); errCode = sd_ble_gap_connect(&peerAddr, - &gapMem.scanParams, + &scanParams, &gapMem.connParams, APP_BLE_CONN_CFG_TAG); ret = bleConvertErrorCode((uint32_t)errCode); diff --git a/sdk/modules/bluetooth/hal/nrf52/ble_gattc.c b/sdk/modules/bluetooth/hal/nrf52/ble_gattc.c index cfd88602d..fb723465a 100644 --- a/sdk/modules/bluetooth/hal/nrf52/ble_gattc.c +++ b/sdk/modules/bluetooth/hal/nrf52/ble_gattc.c @@ -88,6 +88,7 @@ static int nrf52_ble_descriptor_write(uint16_t conn_handle, uint16_t len); static int nrf52_ble_descriptor_read(uint16_t conn_handle, uint16_t handle); +static int nrf52_ble_set_vendor_uuid(BLE_UUID *uuid); /**************************************************************************** * Private Data @@ -108,6 +109,7 @@ static struct ble_hal_gatt_ops_s ble_hal_gatt_ops = .gattc.read = nrf52_ble_gattc_read, .gattc.descriptor_write = nrf52_ble_descriptor_write, .gattc.descriptor_read = nrf52_ble_descriptor_read, + .gattc.set_vendor_uuid = nrf52_ble_set_vendor_uuid, }; /****************************************************************************** @@ -502,6 +504,24 @@ static int nrf52_ble_descriptor_read(uint16_t conn_handle, return bleConvertErrorCode(ret); } +static int nrf52_ble_set_vendor_uuid(BLE_UUID *uuid) +{ + uint32_t errCode; + int ret; + uint8_t uuid_type; + + if (!uuid || (uuid->type != BLE_UUID_TYPE_UUID128)) + { + return -EINVAL; + } + + errCode = sd_ble_uuid_vs_add((ble_uuid128_t *)&uuid->value.uuid128, + &uuid_type); + + ret = bleConvertErrorCode(errCode); + return ret; +} + /**************************************************************************** * Public Functions ****************************************************************************/ diff --git a/sdk/modules/bluetooth/hal/nrf52/ble_storage_operations.c b/sdk/modules/bluetooth/hal/nrf52/ble_storage_operations.c index 7edb63aa1..acc26a836 100644 --- a/sdk/modules/bluetooth/hal/nrf52/ble_storage_operations.c +++ b/sdk/modules/bluetooth/hal/nrf52/ble_storage_operations.c @@ -1,7 +1,7 @@ /**************************************************************************** * modules/bluetooth/hal/nrf52/bt_storage_manager.c * - * Copyright 2022 Sony Semiconductor Solutions Corporation + * Copyright 2022, 2024 Sony Semiconductor Solutions Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -44,8 +44,8 @@ #include #include #include +#include -#include "queue.h" /* TODO: replace to nuttx/include/queue.h */ #include "ble_storage_operations.h" /**************************************************************************** diff --git a/sdk/modules/bluetooth/hal/nrf52/include/ble/ble_gap.h b/sdk/modules/bluetooth/hal/nrf52/include/ble/ble_gap.h index d780b53ce..a2dfd4a8f 100644 --- a/sdk/modules/bluetooth/hal/nrf52/include/ble/ble_gap.h +++ b/sdk/modules/bluetooth/hal/nrf52/include/ble/ble_gap.h @@ -745,6 +745,24 @@ int BLE_GapExchangePairingFeature(BLE_GapConnHandle connHandle, BLE_GapPairingFeature *ownFeature, const BLE_GapPairingFeature *peerFeature); +/**@brief Set scan compatible mode option + * @details Allow connection to legacy peripheral device that do not support + * a Window offset parameter of 0. This enables compatibility mode 1 + * option for nrf52 softdevice. + * + * @param[in] enable: enable if true, disable if false (default: disable) + * @return 0: success + * + * @par Blocking + * Yes + * @par Context + * Task + * @par Reentrant + * No + * + */ +int BLE_GapSetScanCompatMode(bool enable); + /**@brief Set scan parameter * @details This call allows the application to set scan paramter, use the default scan parameter * (interval:200, window:20, timeout:60) if the call of this API is failed or not call this API. @@ -760,7 +778,7 @@ int BLE_GapExchangePairingFeature(BLE_GapConnHandle connHandle, * No * */ -int BLE_GapSetScanParam(BLE_GapScanParams *scanParam); +int BLE_GapSetScanParam(struct ble_scan_param_s *scanParam); /**@brief Start scanning * @details This call allows the application to start scanning. The scanning timeout interval is 60 seconds.The following events may be triggered: @ref BLE_GAP_EVENT_TIMEOUT, @ref BLE_GAP_EVENT_ADV_REPORT. @@ -807,6 +825,21 @@ int BLE_GapStartScanExt(BLE_GapScanParams *scanparams); */ int BLE_GapStopScan(void); +/**@brief Set connection paramter + * @details This call allows to set connection parameter before connecting. + * @param[in] connParam: Pointer to connection parameters + * @return 0: success + * + * @par Blocking + * Yes + * @par Context + * Task + * @par Reentrant + * No + * + */ +int BLE_GapSetConnectionParams(BLE_GapConnParams *connParams); + /**@brief Create a connection * @details This call allows the application to create a connection. The following events may be triggered: @ref BLE_GAP_EVENT_CONNECTED. * @param[in] addr: Pointer to peer address diff --git a/sdk/modules/bluetooth/hal/nrf52/include/ble/ble_gattc.h b/sdk/modules/bluetooth/hal/nrf52/include/ble/ble_gattc.h index 8a905e08d..74887b4e9 100644 --- a/sdk/modules/bluetooth/hal/nrf52/include/ble/ble_gattc.h +++ b/sdk/modules/bluetooth/hal/nrf52/include/ble/ble_gattc.h @@ -54,6 +54,7 @@ #include #include +#include /**************************************************************************** * Pre-processor Definitions @@ -63,8 +64,6 @@ * @{ */ -// #define BLE_DB_DISCOVERY_MAX_SRV 10 /**< Support Max services */ -#define BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV 4 /**< Support Max characteristics per service */ #ifdef CONFIG_BCM20707 #define MAX_VAL_DATA_LENGTH 512 /**< Max value data length. */ #elif defined(CONFIG_BLUETOOTH_NRF52) diff --git a/sdk/modules/bluetooth/hal/nrf52/queue.h b/sdk/modules/bluetooth/hal/nrf52/queue.h deleted file mode 100644 index 37bd61924..000000000 --- a/sdk/modules/bluetooth/hal/nrf52/queue.h +++ /dev/null @@ -1,851 +0,0 @@ -/* $NetBSD: queue.h,v 1.68 2014/11/19 08:10:01 uebayasi Exp $ */ - -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)queue.h 8.5 (Berkeley) 8/20/94 - */ - -#ifndef _SYS_QUEUE_H_ -#define _SYS_QUEUE_H_ - -/* - * This file defines five types of data structures: singly-linked lists, - * lists, simple queues, tail queues, and circular queues. - * - * A singly-linked list is headed by a single forward pointer. The - * elements are singly linked for minimum space and pointer manipulation - * overhead at the expense of O(n) removal for arbitrary elements. New - * elements can be added to the list after an existing element or at the - * head of the list. Elements being removed from the head of the list - * should use the explicit macro for this purpose for optimum - * efficiency. A singly-linked list may only be traversed in the forward - * direction. Singly-linked lists are ideal for applications with large - * datasets and few or no removals or for implementing a LIFO queue. - * - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before - * or after an existing element or at the head of the list. A list - * may only be traversed in the forward direction. - * - * A simple queue is headed by a pair of pointers, one the head of the - * list and the other to the tail of the list. The elements are singly - * linked to save space, so elements can only be removed from the - * head of the list. New elements can be added to the list after - * an existing element, at the head of the list, or at the end of the - * list. A simple queue may only be traversed in the forward direction. - * - * A tail queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or - * after an existing element, at the head of the list, or at the end of - * the list. A tail queue may be traversed in either direction. - * - * A circle queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or after - * an existing element, at the head of the list, or at the end of the list. - * A circle queue may be traversed in either direction, but has a more - * complex end of list detection. - * - * For details on the use of these macros, see the queue(3) manual page. - */ - -/* - * Include the definition of NULL only on NetBSD because sys/null.h - * is not available elsewhere. This conditional makes the header - * portable and it can simply be dropped verbatim into any system. - * The caveat is that on other systems some other header - * must provide NULL before the macros can be used. - */ -#ifdef __NetBSD__ -#include -#endif - -#if defined(QUEUEDEBUG) -# if defined(_KERNEL) -# define QUEUEDEBUG_ABORT(...) panic(__VA_ARGS__) -# else -# include -# define QUEUEDEBUG_ABORT(...) err(1, __VA_ARGS__) -# endif -#endif - -/* - * Singly-linked List definitions. - */ -#define SLIST_HEAD(name, type) \ -struct name { \ - struct type *slh_first; /* first element */ \ -} - -#define SLIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define SLIST_ENTRY(type) \ -struct { \ - struct type *sle_next; /* next element */ \ -} - -/* - * Singly-linked List access methods. - */ -#define SLIST_FIRST(head) ((head)->slh_first) -#define SLIST_END(head) NULL -#define SLIST_EMPTY(head) ((head)->slh_first == NULL) -#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) - -#define SLIST_FOREACH(var, head, field) \ - for((var) = (head)->slh_first; \ - (var) != SLIST_END(head); \ - (var) = (var)->field.sle_next) - -#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = SLIST_FIRST((head)); \ - (var) != SLIST_END(head) && \ - ((tvar) = SLIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -/* - * Singly-linked List functions. - */ -#define SLIST_INIT(head) do { \ - (head)->slh_first = SLIST_END(head); \ -} while (/*CONSTCOND*/0) - -#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ - (elm)->field.sle_next = (slistelm)->field.sle_next; \ - (slistelm)->field.sle_next = (elm); \ -} while (/*CONSTCOND*/0) - -#define SLIST_INSERT_HEAD(head, elm, field) do { \ - (elm)->field.sle_next = (head)->slh_first; \ - (head)->slh_first = (elm); \ -} while (/*CONSTCOND*/0) - -#define SLIST_REMOVE_AFTER(slistelm, field) do { \ - (slistelm)->field.sle_next = \ - SLIST_NEXT(SLIST_NEXT((slistelm), field), field); \ -} while (/*CONSTCOND*/0) - -#define SLIST_REMOVE_HEAD(head, field) do { \ - (head)->slh_first = (head)->slh_first->field.sle_next; \ -} while (/*CONSTCOND*/0) - -#define SLIST_REMOVE(head, elm, type, field) do { \ - if ((head)->slh_first == (elm)) { \ - SLIST_REMOVE_HEAD((head), field); \ - } \ - else { \ - struct type *curelm = (head)->slh_first; \ - while(curelm->field.sle_next != (elm)) \ - curelm = curelm->field.sle_next; \ - curelm->field.sle_next = \ - curelm->field.sle_next->field.sle_next; \ - } \ -} while (/*CONSTCOND*/0) - - -/* - * List definitions. - */ -#define LIST_HEAD(name, type) \ -struct name { \ - struct type *lh_first; /* first element */ \ -} - -#define LIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define LIST_ENTRY(type) \ -struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ -} - -/* - * List access methods. - */ -#define LIST_FIRST(head) ((head)->lh_first) -#define LIST_END(head) NULL -#define LIST_EMPTY(head) ((head)->lh_first == LIST_END(head)) -#define LIST_NEXT(elm, field) ((elm)->field.le_next) - -#define LIST_FOREACH(var, head, field) \ - for ((var) = ((head)->lh_first); \ - (var) != LIST_END(head); \ - (var) = ((var)->field.le_next)) - -#define LIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = LIST_FIRST((head)); \ - (var) != LIST_END(head) && \ - ((tvar) = LIST_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define LIST_MOVE(head1, head2) do { \ - LIST_INIT((head2)); \ - if (!LIST_EMPTY((head1))) { \ - (head2)->lh_first = (head1)->lh_first; \ - LIST_INIT((head1)); \ - } \ -} while (/*CONSTCOND*/0) - -/* - * List functions. - */ -#if defined(QUEUEDEBUG) -#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) \ - if ((head)->lh_first && \ - (head)->lh_first->field.le_prev != &(head)->lh_first) \ - QUEUEDEBUG_ABORT("LIST_INSERT_HEAD %p %s:%d", (head), \ - __FILE__, __LINE__); -#define QUEUEDEBUG_LIST_OP(elm, field) \ - if ((elm)->field.le_next && \ - (elm)->field.le_next->field.le_prev != \ - &(elm)->field.le_next) \ - QUEUEDEBUG_ABORT("LIST_* forw %p %s:%d", (elm), \ - __FILE__, __LINE__); \ - if (*(elm)->field.le_prev != (elm)) \ - QUEUEDEBUG_ABORT("LIST_* back %p %s:%d", (elm), \ - __FILE__, __LINE__); -#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) \ - (elm)->field.le_next = (void *)1L; \ - (elm)->field.le_prev = (void *)1L; -#else -#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) -#define QUEUEDEBUG_LIST_OP(elm, field) -#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) -#endif - -#define LIST_INIT(head) do { \ - (head)->lh_first = LIST_END(head); \ -} while (/*CONSTCOND*/0) - -#define LIST_INSERT_AFTER(listelm, elm, field) do { \ - QUEUEDEBUG_LIST_OP((listelm), field) \ - if (((elm)->field.le_next = (listelm)->field.le_next) != \ - LIST_END(head)) \ - (listelm)->field.le_next->field.le_prev = \ - &(elm)->field.le_next; \ - (listelm)->field.le_next = (elm); \ - (elm)->field.le_prev = &(listelm)->field.le_next; \ -} while (/*CONSTCOND*/0) - -#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ - QUEUEDEBUG_LIST_OP((listelm), field) \ - (elm)->field.le_prev = (listelm)->field.le_prev; \ - (elm)->field.le_next = (listelm); \ - *(listelm)->field.le_prev = (elm); \ - (listelm)->field.le_prev = &(elm)->field.le_next; \ -} while (/*CONSTCOND*/0) - -#define LIST_INSERT_HEAD(head, elm, field) do { \ - QUEUEDEBUG_LIST_INSERT_HEAD((head), (elm), field) \ - if (((elm)->field.le_next = (head)->lh_first) != LIST_END(head))\ - (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ - (head)->lh_first = (elm); \ - (elm)->field.le_prev = &(head)->lh_first; \ -} while (/*CONSTCOND*/0) - -#define LIST_REMOVE(elm, field) do { \ - QUEUEDEBUG_LIST_OP((elm), field) \ - if ((elm)->field.le_next != NULL) \ - (elm)->field.le_next->field.le_prev = \ - (elm)->field.le_prev; \ - *(elm)->field.le_prev = (elm)->field.le_next; \ - QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \ -} while (/*CONSTCOND*/0) - -#define LIST_REPLACE(elm, elm2, field) do { \ - if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ - (elm2)->field.le_next->field.le_prev = \ - &(elm2)->field.le_next; \ - (elm2)->field.le_prev = (elm)->field.le_prev; \ - *(elm2)->field.le_prev = (elm2); \ - QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \ -} while (/*CONSTCOND*/0) - -/* - * Simple queue definitions. - */ -#define SIMPLEQ_HEAD(name, type) \ -struct name { \ - struct type *sqh_first; /* first element */ \ - struct type **sqh_last; /* addr of last next element */ \ -} - -#define SIMPLEQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).sqh_first } - -#define SIMPLEQ_ENTRY(type) \ -struct { \ - struct type *sqe_next; /* next element */ \ -} - -/* - * Simple queue access methods. - */ -#define SIMPLEQ_FIRST(head) ((head)->sqh_first) -#define SIMPLEQ_END(head) NULL -#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == SIMPLEQ_END(head)) -#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) - -#define SIMPLEQ_FOREACH(var, head, field) \ - for ((var) = ((head)->sqh_first); \ - (var) != SIMPLEQ_END(head); \ - (var) = ((var)->field.sqe_next)) - -#define SIMPLEQ_FOREACH_SAFE(var, head, field, next) \ - for ((var) = ((head)->sqh_first); \ - (var) != SIMPLEQ_END(head) && \ - ((next = ((var)->field.sqe_next)), 1); \ - (var) = (next)) - -/* - * Simple queue functions. - */ -#define SIMPLEQ_INIT(head) do { \ - (head)->sqh_first = NULL; \ - (head)->sqh_last = &(head)->sqh_first; \ -} while (/*CONSTCOND*/0) - -#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ - (head)->sqh_last = &(elm)->field.sqe_next; \ - (head)->sqh_first = (elm); \ -} while (/*CONSTCOND*/0) - -#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.sqe_next = NULL; \ - *(head)->sqh_last = (elm); \ - (head)->sqh_last = &(elm)->field.sqe_next; \ -} while (/*CONSTCOND*/0) - -#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ - if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ - (head)->sqh_last = &(elm)->field.sqe_next; \ - (listelm)->field.sqe_next = (elm); \ -} while (/*CONSTCOND*/0) - -#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ - if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ - (head)->sqh_last = &(head)->sqh_first; \ -} while (/*CONSTCOND*/0) - -#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ - if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \ - == NULL) \ - (head)->sqh_last = &(elm)->field.sqe_next; \ -} while (/*CONSTCOND*/0) - -#define SIMPLEQ_REMOVE(head, elm, type, field) do { \ - if ((head)->sqh_first == (elm)) { \ - SIMPLEQ_REMOVE_HEAD((head), field); \ - } else { \ - struct type *curelm = (head)->sqh_first; \ - while (curelm->field.sqe_next != (elm)) \ - curelm = curelm->field.sqe_next; \ - if ((curelm->field.sqe_next = \ - curelm->field.sqe_next->field.sqe_next) == NULL) \ - (head)->sqh_last = &(curelm)->field.sqe_next; \ - } \ -} while (/*CONSTCOND*/0) - -#define SIMPLEQ_CONCAT(head1, head2) do { \ - if (!SIMPLEQ_EMPTY((head2))) { \ - *(head1)->sqh_last = (head2)->sqh_first; \ - (head1)->sqh_last = (head2)->sqh_last; \ - SIMPLEQ_INIT((head2)); \ - } \ -} while (/*CONSTCOND*/0) - -#define SIMPLEQ_LAST(head, type, field) \ - (SIMPLEQ_EMPTY((head)) ? \ - NULL : \ - ((struct type *)(void *) \ - ((char *)((head)->sqh_last) - offsetof(struct type, field)))) - -/* - * Tail queue definitions. - */ -#define _TAILQ_HEAD(name, type, qual) \ -struct name { \ - qual type *tqh_first; /* first element */ \ - qual type *qual *tqh_last; /* addr of last next element */ \ -} -#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,) - -#define TAILQ_HEAD_INITIALIZER(head) \ - { TAILQ_END(head), &(head).tqh_first } - -#define _TAILQ_ENTRY(type, qual) \ -struct { \ - qual type *tqe_next; /* next element */ \ - qual type *qual *tqe_prev; /* address of previous next element */\ -} -#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,) - -/* - * Tail queue access methods. - */ -#define TAILQ_FIRST(head) ((head)->tqh_first) -#define TAILQ_END(head) (NULL) -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) -#define TAILQ_LAST(head, headname) \ - (*(((struct headname *)((head)->tqh_last))->tqh_last)) -#define TAILQ_PREV(elm, headname, field) \ - (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) -#define TAILQ_EMPTY(head) (TAILQ_FIRST(head) == TAILQ_END(head)) - - -#define TAILQ_FOREACH(var, head, field) \ - for ((var) = ((head)->tqh_first); \ - (var) != TAILQ_END(head); \ - (var) = ((var)->field.tqe_next)) - -#define TAILQ_FOREACH_SAFE(var, head, field, next) \ - for ((var) = ((head)->tqh_first); \ - (var) != TAILQ_END(head) && \ - ((next) = TAILQ_NEXT(var, field), 1); (var) = (next)) - -#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ - for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last));\ - (var) != TAILQ_END(head); \ - (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) - -#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, prev) \ - for ((var) = TAILQ_LAST((head), headname); \ - (var) != TAILQ_END(head) && \ - ((prev) = TAILQ_PREV((var), headname, field), 1); (var) = (prev)) - -/* - * Tail queue functions. - */ -#if defined(QUEUEDEBUG) -#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) \ - if ((head)->tqh_first && \ - (head)->tqh_first->field.tqe_prev != &(head)->tqh_first) \ - QUEUEDEBUG_ABORT("TAILQ_INSERT_HEAD %p %s:%d", (head), \ - __FILE__, __LINE__); -#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) \ - if (*(head)->tqh_last != NULL) \ - QUEUEDEBUG_ABORT("TAILQ_INSERT_TAIL %p %s:%d", (head), \ - __FILE__, __LINE__); -#define QUEUEDEBUG_TAILQ_OP(elm, field) \ - if ((elm)->field.tqe_next && \ - (elm)->field.tqe_next->field.tqe_prev != \ - &(elm)->field.tqe_next) \ - QUEUEDEBUG_ABORT("TAILQ_* forw %p %s:%d", (elm), \ - __FILE__, __LINE__); \ - if (*(elm)->field.tqe_prev != (elm)) \ - QUEUEDEBUG_ABORT("TAILQ_* back %p %s:%d", (elm), \ - __FILE__, __LINE__); -#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) \ - if ((elm)->field.tqe_next == NULL && \ - (head)->tqh_last != &(elm)->field.tqe_next) \ - QUEUEDEBUG_ABORT("TAILQ_PREREMOVE head %p elm %p %s:%d",\ - (head), (elm), __FILE__, __LINE__); -#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) \ - (elm)->field.tqe_next = (void *)1L; \ - (elm)->field.tqe_prev = (void *)1L; -#else -#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) -#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) -#define QUEUEDEBUG_TAILQ_OP(elm, field) -#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) -#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) -#endif - -#define TAILQ_INIT(head) do { \ - (head)->tqh_first = TAILQ_END(head); \ - (head)->tqh_last = &(head)->tqh_first; \ -} while (/*CONSTCOND*/0) - -#define TAILQ_INSERT_HEAD(head, elm, field) do { \ - QUEUEDEBUG_TAILQ_INSERT_HEAD((head), (elm), field) \ - if (((elm)->field.tqe_next = (head)->tqh_first) != TAILQ_END(head))\ - (head)->tqh_first->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (head)->tqh_first = (elm); \ - (elm)->field.tqe_prev = &(head)->tqh_first; \ -} while (/*CONSTCOND*/0) - -#define TAILQ_INSERT_TAIL(head, elm, field) do { \ - QUEUEDEBUG_TAILQ_INSERT_TAIL((head), (elm), field) \ - (elm)->field.tqe_next = TAILQ_END(head); \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &(elm)->field.tqe_next; \ -} while (/*CONSTCOND*/0) - -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ - QUEUEDEBUG_TAILQ_OP((listelm), field) \ - if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != \ - TAILQ_END(head)) \ - (elm)->field.tqe_next->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (listelm)->field.tqe_next = (elm); \ - (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ -} while (/*CONSTCOND*/0) - -#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ - QUEUEDEBUG_TAILQ_OP((listelm), field) \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - (elm)->field.tqe_next = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ -} while (/*CONSTCOND*/0) - -#define TAILQ_REMOVE(head, elm, field) do { \ - QUEUEDEBUG_TAILQ_PREREMOVE((head), (elm), field) \ - QUEUEDEBUG_TAILQ_OP((elm), field) \ - if (((elm)->field.tqe_next) != TAILQ_END(head)) \ - (elm)->field.tqe_next->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ - QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \ -} while (/*CONSTCOND*/0) - -#define TAILQ_REPLACE(head, elm, elm2, field) do { \ - if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != \ - TAILQ_END(head)) \ - (elm2)->field.tqe_next->field.tqe_prev = \ - &(elm2)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm2)->field.tqe_next; \ - (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ - *(elm2)->field.tqe_prev = (elm2); \ - QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \ -} while (/*CONSTCOND*/0) - -#define TAILQ_CONCAT(head1, head2, field) do { \ - if (!TAILQ_EMPTY(head2)) { \ - *(head1)->tqh_last = (head2)->tqh_first; \ - (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ - (head1)->tqh_last = (head2)->tqh_last; \ - TAILQ_INIT((head2)); \ - } \ -} while (/*CONSTCOND*/0) - -/* - * Singly-linked Tail queue declarations. - */ -#define STAILQ_HEAD(name, type) \ -struct name { \ - struct type *stqh_first; /* first element */ \ - struct type **stqh_last; /* addr of last next element */ \ -} - -#define STAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).stqh_first } - -#define STAILQ_ENTRY(type) \ -struct { \ - struct type *stqe_next; /* next element */ \ -} - -/* - * Singly-linked Tail queue access methods. - */ -#define STAILQ_FIRST(head) ((head)->stqh_first) -#define STAILQ_END(head) NULL -#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) -#define STAILQ_EMPTY(head) (STAILQ_FIRST(head) == STAILQ_END(head)) - -/* - * Singly-linked Tail queue functions. - */ -#define STAILQ_INIT(head) do { \ - (head)->stqh_first = NULL; \ - (head)->stqh_last = &(head)->stqh_first; \ -} while (/*CONSTCOND*/0) - -#define STAILQ_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ - (head)->stqh_last = &(elm)->field.stqe_next; \ - (head)->stqh_first = (elm); \ -} while (/*CONSTCOND*/0) - -#define STAILQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.stqe_next = NULL; \ - *(head)->stqh_last = (elm); \ - (head)->stqh_last = &(elm)->field.stqe_next; \ -} while (/*CONSTCOND*/0) - -#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ - if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\ - (head)->stqh_last = &(elm)->field.stqe_next; \ - (listelm)->field.stqe_next = (elm); \ -} while (/*CONSTCOND*/0) - -#define STAILQ_REMOVE_HEAD(head, field) do { \ - if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \ - (head)->stqh_last = &(head)->stqh_first; \ -} while (/*CONSTCOND*/0) - -#define STAILQ_REMOVE(head, elm, type, field) do { \ - if ((head)->stqh_first == (elm)) { \ - STAILQ_REMOVE_HEAD((head), field); \ - } else { \ - struct type *curelm = (head)->stqh_first; \ - while (curelm->field.stqe_next != (elm)) \ - curelm = curelm->field.stqe_next; \ - if ((curelm->field.stqe_next = \ - curelm->field.stqe_next->field.stqe_next) == NULL) \ - (head)->stqh_last = &(curelm)->field.stqe_next; \ - } \ -} while (/*CONSTCOND*/0) - -#define STAILQ_FOREACH(var, head, field) \ - for ((var) = ((head)->stqh_first); \ - (var); \ - (var) = ((var)->field.stqe_next)) - -#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = STAILQ_FIRST((head)); \ - (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define STAILQ_CONCAT(head1, head2) do { \ - if (!STAILQ_EMPTY((head2))) { \ - *(head1)->stqh_last = (head2)->stqh_first; \ - (head1)->stqh_last = (head2)->stqh_last; \ - STAILQ_INIT((head2)); \ - } \ -} while (/*CONSTCOND*/0) - -#define STAILQ_LAST(head, type, field) \ - (STAILQ_EMPTY((head)) ? \ - NULL : \ - ((struct type *)(void *) \ - ((char *)((head)->stqh_last) - offsetof(struct type, field)))) - - -#ifndef _KERNEL -/* - * Circular queue definitions. Do not use. We still keep the macros - * for compatibility but because of pointer aliasing issues their use - * is discouraged! - */ - -/* - * __launder_type(): We use this ugly hack to work around the the compiler - * noticing that two types may not alias each other and elide tests in code. - * We hit this in the CIRCLEQ macros when comparing 'struct name *' and - * 'struct type *' (see CIRCLEQ_HEAD()). Modern compilers (such as GCC - * 4.8) declare these comparisons as always false, causing the code to - * not run as designed. - * - * This hack is only to be used for comparisons and thus can be fully const. - * Do not use for assignment. - * - * If we ever choose to change the ABI of the CIRCLEQ macros, we could fix - * this by changing the head/tail sentinal values, but see the note above - * this one. - */ - -#if defined(__GNUC__) && !defined(__CC_ARM) -static __inline const void * __launder_type(const void *); -static __inline const void * -__launder_type(const void *__x) -{ - __asm __volatile("" : "+r" (__x)); - return __x; -} -#else /* defined(__GNUC__) && !defined(__CC_ARM) */ -#define __launder_type(arg) (arg) -#endif /* defined(__GNUC__) && !defined(__CC_ARM) */ - -#if defined(QUEUEDEBUG) -#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field) \ - if ((head)->cqh_first != CIRCLEQ_ENDC(head) && \ - (head)->cqh_first->field.cqe_prev != CIRCLEQ_ENDC(head)) \ - QUEUEDEBUG_ABORT("CIRCLEQ head forw %p %s:%d", (head), \ - __FILE__, __LINE__); \ - if ((head)->cqh_last != CIRCLEQ_ENDC(head) && \ - (head)->cqh_last->field.cqe_next != CIRCLEQ_ENDC(head)) \ - QUEUEDEBUG_ABORT("CIRCLEQ head back %p %s:%d", (head), \ - __FILE__, __LINE__); -#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field) \ - if ((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) { \ - if ((head)->cqh_last != (elm)) \ - QUEUEDEBUG_ABORT("CIRCLEQ elm last %p %s:%d", \ - (elm), __FILE__, __LINE__); \ - } else { \ - if ((elm)->field.cqe_next->field.cqe_prev != (elm)) \ - QUEUEDEBUG_ABORT("CIRCLEQ elm forw %p %s:%d", \ - (elm), __FILE__, __LINE__); \ - } \ - if ((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) { \ - if ((head)->cqh_first != (elm)) \ - QUEUEDEBUG_ABORT("CIRCLEQ elm first %p %s:%d", \ - (elm), __FILE__, __LINE__); \ - } else { \ - if ((elm)->field.cqe_prev->field.cqe_next != (elm)) \ - QUEUEDEBUG_ABORT("CIRCLEQ elm prev %p %s:%d", \ - (elm), __FILE__, __LINE__); \ - } -#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field) \ - (elm)->field.cqe_next = (void *)1L; \ - (elm)->field.cqe_prev = (void *)1L; -#else -#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field) -#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field) -#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field) -#endif - -#define CIRCLEQ_HEAD(name, type) \ -struct name { \ - struct type *cqh_first; /* first element */ \ - struct type *cqh_last; /* last element */ \ -} - -#define CIRCLEQ_HEAD_INITIALIZER(head) \ - { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } - -#define CIRCLEQ_ENTRY(type) \ -struct { \ - struct type *cqe_next; /* next element */ \ - struct type *cqe_prev; /* previous element */ \ -} - -/* - * Circular queue functions. - */ -#define CIRCLEQ_INIT(head) do { \ - (head)->cqh_first = CIRCLEQ_END(head); \ - (head)->cqh_last = CIRCLEQ_END(head); \ -} while (/*CONSTCOND*/0) - -#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ - QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ - QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \ - (elm)->field.cqe_next = (listelm)->field.cqe_next; \ - (elm)->field.cqe_prev = (listelm); \ - if ((listelm)->field.cqe_next == CIRCLEQ_ENDC(head)) \ - (head)->cqh_last = (elm); \ - else \ - (listelm)->field.cqe_next->field.cqe_prev = (elm); \ - (listelm)->field.cqe_next = (elm); \ -} while (/*CONSTCOND*/0) - -#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ - QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ - QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \ - (elm)->field.cqe_next = (listelm); \ - (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ - if ((listelm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \ - (head)->cqh_first = (elm); \ - else \ - (listelm)->field.cqe_prev->field.cqe_next = (elm); \ - (listelm)->field.cqe_prev = (elm); \ -} while (/*CONSTCOND*/0) - -#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ - QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ - (elm)->field.cqe_next = (head)->cqh_first; \ - (elm)->field.cqe_prev = CIRCLEQ_END(head); \ - if ((head)->cqh_last == CIRCLEQ_ENDC(head)) \ - (head)->cqh_last = (elm); \ - else \ - (head)->cqh_first->field.cqe_prev = (elm); \ - (head)->cqh_first = (elm); \ -} while (/*CONSTCOND*/0) - -#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ - QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ - (elm)->field.cqe_next = CIRCLEQ_END(head); \ - (elm)->field.cqe_prev = (head)->cqh_last; \ - if ((head)->cqh_first == CIRCLEQ_ENDC(head)) \ - (head)->cqh_first = (elm); \ - else \ - (head)->cqh_last->field.cqe_next = (elm); \ - (head)->cqh_last = (elm); \ -} while (/*CONSTCOND*/0) - -#define CIRCLEQ_REMOVE(head, elm, field) do { \ - QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ - QUEUEDEBUG_CIRCLEQ_ELM((head), (elm), field) \ - if ((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) \ - (head)->cqh_last = (elm)->field.cqe_prev; \ - else \ - (elm)->field.cqe_next->field.cqe_prev = \ - (elm)->field.cqe_prev; \ - if ((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \ - (head)->cqh_first = (elm)->field.cqe_next; \ - else \ - (elm)->field.cqe_prev->field.cqe_next = \ - (elm)->field.cqe_next; \ - QUEUEDEBUG_CIRCLEQ_POSTREMOVE((elm), field) \ -} while (/*CONSTCOND*/0) - -#define CIRCLEQ_FOREACH(var, head, field) \ - for ((var) = ((head)->cqh_first); \ - (var) != CIRCLEQ_ENDC(head); \ - (var) = ((var)->field.cqe_next)) - -#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ - for ((var) = ((head)->cqh_last); \ - (var) != CIRCLEQ_ENDC(head); \ - (var) = ((var)->field.cqe_prev)) - -/* - * Circular queue access methods. - */ -#define CIRCLEQ_FIRST(head) ((head)->cqh_first) -#define CIRCLEQ_LAST(head) ((head)->cqh_last) -/* For comparisons */ -#define CIRCLEQ_ENDC(head) (__launder_type(head)) -/* For assignments */ -#define CIRCLEQ_END(head) ((void *)(head)) -#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) -#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) -#define CIRCLEQ_EMPTY(head) \ - (CIRCLEQ_FIRST(head) == CIRCLEQ_ENDC(head)) - -#define CIRCLEQ_LOOP_NEXT(head, elm, field) \ - (((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) \ - ? ((head)->cqh_first) \ - : (elm->field.cqe_next)) -#define CIRCLEQ_LOOP_PREV(head, elm, field) \ - (((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \ - ? ((head)->cqh_last) \ - : (elm->field.cqe_prev)) -#endif /* !_KERNEL */ - -#endif /* !_SYS_QUEUE_H_ */ diff --git a/sdk/modules/fwuputils/clients/Make.defs b/sdk/modules/fwuputils/clients/Make.defs index 1815f996c..812230928 100644 --- a/sdk/modules/fwuputils/clients/Make.defs +++ b/sdk/modules/fwuputils/clients/Make.defs @@ -36,11 +36,7 @@ ifeq ($(CONFIG_FWUPUTILS_CLIENTS),y) CSRCS += fwup_client.c -ifeq ($(WINTOOL),y) -CFLAGS += -I "${shell cygpath -w $(SDKDIR)$(DELIM)bsp$(DELIM)src}" -else -CFLAGS += -I$(SDKDIR)$(DELIM)bsp$(DELIM)src -endif + VPATH += clients DEPPATH += --dep-path clients diff --git a/sdk/modules/include/asmp/delay.h b/sdk/modules/include/asmp/delay.h new file mode 100644 index 000000000..211f50eb4 --- /dev/null +++ b/sdk/modules/include/asmp/delay.h @@ -0,0 +1,6 @@ +#ifndef __INCLUDE_ASMP_DELAY_H +#define __INCLUDE_ASMP_DELAY_H + +#include + +#endif /* __INCLUDE_ASMP_DELAY_H */ diff --git a/sdk/modules/include/asmp/stdio.h b/sdk/modules/include/asmp/stdio.h new file mode 100644 index 000000000..3fa2d1a68 --- /dev/null +++ b/sdk/modules/include/asmp/stdio.h @@ -0,0 +1,58 @@ +/**************************************************************************** + * modules/include/asmp/stdio.h + * + * Copyright 2024 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __INCLUDE_ASMP_STDIO_H +#define __INCLUDE_ASMP_STDIO_H + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* For debug use only */ + +int putchar(const char c); +int puts(const char *str); +int printf(const char *fmt, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_ASMP_STDIO_H */ diff --git a/sdk/modules/include/asmp/types.h b/sdk/modules/include/asmp/types.h index da2f55686..704a660aa 100644 --- a/sdk/modules/include/asmp/types.h +++ b/sdk/modules/include/asmp/types.h @@ -70,12 +70,6 @@ typedef int16_t cpuid_t; typedef int16_t mpobjtype_t; -/* This typedef is supplemental */ - -#ifndef CONFIG_SMP -typedef volatile uint8_t cpu_set_t; -#endif - /* * Super class for MP objects */ diff --git a/sdk/modules/include/audiolite/al_component.h b/sdk/modules/include/audiolite/al_component.h index e76318b04..0cd2ac993 100644 --- a/sdk/modules/include/audiolite/al_component.h +++ b/sdk/modules/include/audiolite/al_component.h @@ -40,6 +40,8 @@ * Included Files ****************************************************************************/ +#include + #include #include #include @@ -88,8 +90,8 @@ class audiolite_component : public audiolite_nodecomm_if int outputnum = 1, int depth = 16, bool is_sync = true, - int prio = -1, - int stack_sz = -1); + int prio = 105, + int stack_sz = CONFIG_PTHREAD_STACK_DEFAULT); virtual ~audiolite_component(); void set_mempool(audiolite_mempool *pool); @@ -129,11 +131,16 @@ class audiolite_component : public audiolite_nodecomm_if audiolite_inputnode *get_input(int id = 0); audiolite_outputnode *get_output(int id = 0); - int bind(audiolite_component *cmp); + audiolite_component *bind(audiolite_component *cmp); int bind(audiolite_inputnode *in, int outid = 0); int unbind(audiolite_inputnode *in); int unbindall(); + + virtual int start(); + virtual void stop(); + virtual void suspend(); + virtual int resume(); }; #endif /* __INCLUDE_AUDIOLITE_COMPONENT_H */ diff --git a/sdk/modules/include/audiolite/al_decoder.h b/sdk/modules/include/audiolite/al_decoder.h index 73284214d..10ce04c78 100644 --- a/sdk/modules/include/audiolite/al_decoder.h +++ b/sdk/modules/include/audiolite/al_decoder.h @@ -41,7 +41,7 @@ ****************************************************************************/ #include -#include +#include #include /**************************************************************************** @@ -52,10 +52,11 @@ * class: audiolite_decoder ****************************************************************************/ -class audiolite_decoder : public audiolite_source +class audiolite_decoder : public audiolite_component { protected: audiolite_stream *_stream; + audiolite_mempoolapbuf *_omempool; int _prio; int _stacksz; mossfw_thread_t _tid; @@ -86,6 +87,10 @@ class audiolite_decoder : public audiolite_source virtual int resume_decode() = 0; void set_stream(audiolite_stream *st) { _stream = st; }; + void set_outputmempool(audiolite_mempoolapbuf *pool) + { + _omempool = pool; + } }; #endif /* __INCLUDE_AUDIOLITE_DECODER_H */ diff --git a/sdk/modules/include/audiolite/al_eventlistener.h b/sdk/modules/include/audiolite/al_eventlistener.h index 1ce0f9a93..569c71249 100644 --- a/sdk/modules/include/audiolite/al_eventlistener.h +++ b/sdk/modules/include/audiolite/al_eventlistener.h @@ -65,13 +65,19 @@ #define AL_EVENT_SENDERROR (-20) #define AL_EVENT_MP3FRAMEINFO (-21) #define AL_EVENT_MP3DECWORKEREND (-22) -#define AL_EVENT_MP3DECUNKNOWNEVT (-23) +#define AL_EVENT_UNKNOWN (-23) #define AL_EVENT_MP3DECERROR (-24) #define AL_EVENT_MP3DEC_WRONGTYPE (-25) -#define AL_EVENT_MP3DEC_WRONGVER (-26) +#define AL_EVENT_WRONGVERSION (-26) class audiolite_component; +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +const char *audiolite_strevent(int evt); + /**************************************************************************** * Class Definitions ****************************************************************************/ @@ -88,4 +94,19 @@ class audiolite_eventlistener unsigned long arg){}; }; +/**************************************************************************** + * Class: audiolite_simplelistener + ****************************************************************************/ + +class audiolite_simplelistener : public audiolite_eventlistener +{ + public: + void on_event(int evt, audiolite_component *cmp, + unsigned long arg) + { + printf("AudioLite Event %s is happened : %d\n", + audiolite_strevent(evt), (int)arg); + } +}; + #endif /* __INCLUDE_AUDIOLITE_EVENT_LISTENER_H */ diff --git a/sdk/modules/include/audiolite/al_inputcomp.h b/sdk/modules/include/audiolite/al_inputcomp.h index aad2a8075..3e80efc57 100644 --- a/sdk/modules/include/audiolite/al_inputcomp.h +++ b/sdk/modules/include/audiolite/al_inputcomp.h @@ -40,7 +40,7 @@ * Included Files ****************************************************************************/ -#include +#include #include /**************************************************************************** @@ -51,7 +51,7 @@ * class: audiolite_component ****************************************************************************/ -class audiolite_inputcomp : public audiolite_source, +class audiolite_inputcomp : public audiolite_component, public audiolite_drvlistener { private: @@ -91,13 +91,6 @@ class audiolite_inputcomp : public audiolite_source, void on_underflowed(void){ /* Never happened. */ }; void on_popeddata(struct ap_buffer_s *apb); void on_overflowed(void); - - /* Inherited member functions from audiolite_source */ - - int start(); - void stop(); - void pause(); - int resume(); }; #endif /* __INCLUDE_AUDIOLITE_INPUT_COMPONENT_H */ diff --git a/sdk/modules/include/audiolite/al_memalloc.h b/sdk/modules/include/audiolite/al_memalloc.h index b7d6535b8..dc9015802 100644 --- a/sdk/modules/include/audiolite/al_memalloc.h +++ b/sdk/modules/include/audiolite/al_memalloc.h @@ -101,6 +101,7 @@ class audiolite_mempool : public audiolite_timeprofile virtual void memfree(audiolite_mem *mem) = 0; virtual void disable_pool() = 0; virtual void enable_pool() = 0; + virtual int remaining() = 0; }; /**************************************************************************** @@ -203,6 +204,7 @@ class audiolite_mempoolapbuf : public audiolite_mempool virtual void memfree(audiolite_mem *mem); void disable_pool(); void enable_pool(); + int remaining(); }; /**************************************************************************** @@ -264,6 +266,7 @@ class audiolite_mempoolsysmsg : public audiolite_mempool virtual void memfree(audiolite_mem *mem); void disable_pool(); void enable_pool(); + int remaining(); }; #endif /* __INCLUDE_AUDIOLITE_MEMALLOC_H */ diff --git a/sdk/modules/include/audiolite/al_mp3dec.h b/sdk/modules/include/audiolite/al_mp3dec.h index 899fa96ed..9d1f122f8 100644 --- a/sdk/modules/include/audiolite/al_mp3dec.h +++ b/sdk/modules/include/audiolite/al_mp3dec.h @@ -56,11 +56,12 @@ class audiolite_mp3dec : public audiolite_decoder { private: - audiolite_mempoolapbuf *_omempool; audiolite_worker _worker; audiolite_workermemq _inq; audiolite_workermemq _outq; bool _frame_eof; + volatile bool _worker_booted; + volatile bool _worker_terminated; static int handle_mesage(al_comm_msghdr_t hdr, al_comm_msgopt_t *opt, void *arg); @@ -76,11 +77,6 @@ class audiolite_mp3dec : public audiolite_decoder int stop_decode(); int pause_decode() { return OK; }; int resume_decode() { return OK; }; - - void set_outputmempool(audiolite_mempoolapbuf *pool) - { - _omempool = pool; - } }; #endif /* __INCLUDE_AUDIOLITE_MP3DEC_H */ diff --git a/sdk/modules/include/audiolite/al_outputcomp.h b/sdk/modules/include/audiolite/al_outputcomp.h index a1ddd6564..110704540 100644 --- a/sdk/modules/include/audiolite/al_outputcomp.h +++ b/sdk/modules/include/audiolite/al_outputcomp.h @@ -55,6 +55,7 @@ class audiolite_outputcomp : public audiolite_component, public audiolite_drvlistener { private: + volatile bool enqueue_enable; audiolite_driver *_driver; public: diff --git a/sdk/modules/include/audiolite/al_thread.h b/sdk/modules/include/audiolite/al_thread.h new file mode 100644 index 000000000..c13f2f3c7 --- /dev/null +++ b/sdk/modules/include/audiolite/al_thread.h @@ -0,0 +1,73 @@ +#ifndef __INCLUDE_AUDIOLITE_THREAD_H +#define __INCLUDE_AUDIOLITE_THREAD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define AL_THREAD_NAMEMAX (32) + +/**************************************************************************** + * Class Definitions + ****************************************************************************/ + +class audiolite_runnable_if +{ + public: + + /* Override before_start() method if there is any conditions before + * start run the thread. + * Retrun true if all conditions are good enough, + * return false if it is not. + */ + + virtual bool before_start(void *arg) + { + return true; + }; + + /* runnable returns 0 when it wants to finish the thread loop. + * Returning othre value makes keep continue the loop. + */ + + virtual int run(void *arg) = 0; + + /* Override before_stop() method to do some before thread is stopped. */ + + virtual void before_stop(void *arg) {}; +}; + +class audiolite_thread +{ + protected: + audiolite_runnable_if *_runnable; + void *_runnable_arg; + + mossfw_thread_t _tid; + int _prio; + int _stacksz; + char _tname[AL_THREAD_NAMEMAX]; + volatile bool _is_thrdrun; + + static void *running_thread(void *arg); + + public: + audiolite_thread(audiolite_runnable_if *runnable, void *runnable_arg, + int prio, int stacksz, const char *thdname=NULL); + + ~audiolite_thread(); + + bool set_runnable(audiolite_runnable_if *runnable, void *runnable_arg); + bool start(); + void stop(); + + bool is_running() { return _is_thrdrun; }; +}; + +#endif // __INCLUDE_AUDIOLITE_THREAD_H diff --git a/sdk/modules/include/audiolite/al_worker.h b/sdk/modules/include/audiolite/al_worker.h index 68d9f8f14..a2e5d8e20 100644 --- a/sdk/modules/include/audiolite/al_worker.h +++ b/sdk/modules/include/audiolite/al_worker.h @@ -88,7 +88,9 @@ class audiolite_workermemq void push(audiolite_memapbuf *mem); audiolite_memapbuf *pop(); + audiolite_memapbuf *pop(unsigned char *addr); int get_qsize() { return _max_qsz; }; + int current_sz() { return dq_count(&_mem_proc); }; }; /**************************************************************************** diff --git a/sdk/modules/include/audiolite/al_workercmd.h b/sdk/modules/include/audiolite/al_workercmd.h index 9130a31d4..12f15619b 100644 --- a/sdk/modules/include/audiolite/al_workercmd.h +++ b/sdk/modules/include/audiolite/al_workercmd.h @@ -54,9 +54,11 @@ int alworker_send_systemparam(al_wtask_t *wtask, int alworker_send_startframe(al_wtask_t *wtask); int alworker_send_instgain(al_wtask_t *wtask, float gain); int alworker_send_start(al_wtask_t *wtask); +int alworker_send_stop(al_wtask_t *wtask); int alworker_send_term(al_wtask_t *wtask); int alworker_inject_omem(al_wtask_t *wtask, audiolite_mem *mem); int alworker_inject_imem(al_wtask_t *wtask, audiolite_mem *mem); +int alworker_send_resp(al_wtask_t *wtask, al_comm_msghdr_t hdr, int ret); #endif /* __INCLUDE_AUDIOLITE_WORKERCMD_H */ diff --git a/sdk/modules/include/audiolite/al_workercomp.h b/sdk/modules/include/audiolite/al_workercomp.h new file mode 100644 index 000000000..3334ed7ab --- /dev/null +++ b/sdk/modules/include/audiolite/al_workercomp.h @@ -0,0 +1,141 @@ +#ifndef __INCLUDE_AUDIOLITE_WORKERCOMP_H +#define __INCLUDE_AUDIOLITE_WORKERCOMP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define WORKERCOMP_SPKNAMESZ (32) + +/**************************************************************************** + * Class Pre-definitions + ****************************************************************************/ + +class audiolite_workercomp; + +/**************************************************************************** + * Class Definitions + ****************************************************************************/ + +class audiolite_stdworker_msglistener +{ + public: + virtual void bootup(audiolite_workercomp *wcomp, al_wtask_t *wtask, + int version, void *d) + { + }; + + virtual void error(audiolite_workercomp *wcomp, al_wtask_t *wtask, + int id, int ercode) + { + }; + + virtual void debug(audiolite_workercomp *wcomp, al_wtask_t *wtask, + int code) + { + }; + + virtual void info(audiolite_workercomp *wcomp, al_wtask_t *wtask, + int id, int chs, int fs, int layer, int rate) + { + }; + + virtual void done(audiolite_workercomp *wcomp, al_wtask_t *wtask, + int id) + { + }; + + virtual void term(audiolite_workercomp *wcomp) + { + }; + + virtual audiolite_memapbuf *release_inmem(audiolite_workercomp *wcomp, + al_wtask_t *wtask, + audiolite_memapbuf *mem, + int size) + { + return NULL; + }; + + virtual audiolite_memapbuf *release_outmem(audiolite_workercomp *wcomp, + al_wtask_t *wtask, + audiolite_memapbuf *mem) + { + push_data(wcomp, mem); + return NULL; + }; + + virtual void usermsg(audiolite_workercomp *wcomp, al_wtask_t *wtask, + al_comm_msghdr_t hdr, al_comm_msgopt_t *opt) + { + }; + + void push_data(audiolite_workercomp *wcomp, audiolite_memapbuf *mem); + int get_inqsize(audiolite_workercomp *wcomp); + int get_outqsize(audiolite_workercomp *wcomp); + audiolite_memapbuf *allocate(audiolite_workercomp *wcomp); +}; + +class audiolite_workercomp : public audiolite_component, audiolite_runnable_if +{ + protected: + char _workerspk[WORKERCOMP_SPKNAMESZ]; + audiolite_worker _worker; + audiolite_workermemq _inq; + audiolite_workermemq _outq; + bool _worker_booted; + bool _worker_terminated; + audiolite_stdworker_msglistener *_lsnr; + audiolite_thread _thd; + + static int handle_message(al_comm_msghdr_t hdr, + al_comm_msgopt_t *opt, void *arg); + + int start_worker(); + void stop_worker(); + + public: + audiolite_workercomp(const char *workername, + int inqsz, + int outqsz, + int inputnum = 1, + int outputnum = 1, + int depth = 16, + int prio = 105, + int stack_sz = 2048); + + virtual ~audiolite_workercomp(); + + void set_msglistener(audiolite_stdworker_msglistener *lsnr) + { + _lsnr = lsnr; + } + + /* Inherited methods from audiolite_component */ + + virtual void on_data(); + virtual int on_starting(audiolite_inputnode *inode, + audiolite_outputnode *onode); + virtual void on_canceled(audiolite_inputnode *inode, + audiolite_outputnode *onode); + virtual void on_stopping(audiolite_inputnode *inode, + audiolite_outputnode *onode); + + /* Inherited methods from audiolite_stdworker_msglistener */ + + virtual bool before_start(void *arg); + virtual int run(void *arg); + virtual void before_stop(void *arg); + + friend class audiolite_stdworker_msglistener; +}; + +#endif /* __INCLUDE_AUDIOLITE_WORKERCOMP_H */ diff --git a/sdk/modules/include/audiolite/alworker_comm.h b/sdk/modules/include/audiolite/alworker_comm.h index 9cdb2b940..a7f7b6ce7 100644 --- a/sdk/modules/include/audiolite/alworker_comm.h +++ b/sdk/modules/include/audiolite/alworker_comm.h @@ -59,10 +59,12 @@ #define AL_COMM_MESSAGE_FMEM (2) #define AL_COMM_MESSAGE_OMEM (3) #define AL_COMM_MESSAGE_INST (4) +#define AL_COMM_MESSAGE_USER (5) #define AL_COMM_MSGTYPE_NONE (0) #define AL_COMM_MSGTYPE_ASYNC (1) #define AL_COMM_MSGTYPE_SYNC (2) +#define AL_COMM_MSGTYPE_RESP (3) #define AL_COMM_MSGCODESYS_NONE (0) #define AL_COMM_MSGCODESYS_STOP (1) @@ -95,6 +97,7 @@ #define AL_COMM_MSGCODEERR_INVALIDINST (7) #define AL_COMM_MSGCODEERR_MULTIFRAME (8) #define AL_COMM_MSGCODEERR_UNSUPFRAME (9) +#define AL_COMM_MSGCODEERR_INVALIDSTATE (10) #define AL_COMM_ERR_SUCCESS (0) #define AL_COMM_ERR_WORKERINIT (-1) @@ -108,14 +111,20 @@ #define AL_WORKER_VERSION_0 (0) #define AL_WORKER_VERSION_1 (1) +#define AL_WORKER_VERSION_2 (2) -#define AL_MP3DECWORKER_VERSION AL_WORKER_VERSION_1 +#define AL_MP3DECWORKER_VERSION AL_WORKER_VERSION_2 #define AL_COMM_NO_MSG (0xffffffff) #define AL_MSGBUF_DEPTH_POW (4) #define AL_MSGBUF_DEPTH (1 << AL_MSGBUF_DEPTH_POW) +#define AL_COMM_MSGGRP(h) ((h)->grp) +#define AL_COMM_MSGTYPE(h) ((h)->type) +#define AL_COMM_MSGCODE(h) ((h)->code) +#define AL_COMM_MSGOPT(h) ((h)->opt) + /**************************************************************************** * Public Types ****************************************************************************/ @@ -159,6 +168,7 @@ union al_comm_msgopt_u }; int errcode; float gain; + int usr[4]; }; typedef union al_comm_msgopt_u al_comm_msgopt_t; diff --git a/sdk/modules/include/audiolite/audiolite.h b/sdk/modules/include/audiolite/audiolite.h index b225424cf..18eaa844a 100644 --- a/sdk/modules/include/audiolite/audiolite.h +++ b/sdk/modules/include/audiolite/audiolite.h @@ -54,13 +54,14 @@ #include #include #include -#include #include #include #include #include #include +#include #include +#include #include #include diff --git a/sdk/modules/include/bluetooth/ble_gatt.h b/sdk/modules/include/bluetooth/ble_gatt.h index 29aee0e93..e9d315820 100644 --- a/sdk/modules/include/bluetooth/ble_gatt.h +++ b/sdk/modules/include/bluetooth/ble_gatt.h @@ -621,6 +621,17 @@ int ble_continue_db_discovery(uint16_t start_handle, uint16_t conn_handle); int ble_discover_uuid(uint16_t conn_handle, BLE_UUID *srv_uuid, BLE_UUID *char_uuid); +/** + * @brief Set vendor specific UUID + * This API allows the vendor specific UUID to be discovered. + * + * @param[in] uuid: Vendor Specific UUID (128 bit) + * + * @retval error code + */ + +int ble_set_vendor_uuid(BLE_UUID *uuid); + #undef EXTERN #ifdef __cplusplus } diff --git a/sdk/modules/include/bluetooth/ble_util.h b/sdk/modules/include/bluetooth/ble_util.h index 8a93e4800..147b5f7ef 100755 --- a/sdk/modules/include/bluetooth/ble_util.h +++ b/sdk/modules/include/bluetooth/ble_util.h @@ -1,7 +1,7 @@ /**************************************************************************** * sdk/modules/include/bluetooth/ble_util.h * - * Copyright 2023 Sony Semiconductor Solutions Corporation + * Copyright 2023, 2024 Sony Semiconductor Solutions Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -45,6 +45,14 @@ #include #include +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + /**************************************************************************** * Public Functions Prototypes ****************************************************************************/ @@ -140,6 +148,17 @@ int bleutil_get_devicename(uint8_t *data, uint8_t len, char *devname); BLE_ADDRESS_TYPE bleutil_get_addrtype(uint8_t *data, uint8_t len); +/* name: bleutil_get_rssi + * Get BLE RSSI value from advertising data + * + * data [in] : Advertising data + * len [in] : Advertising data length in bytes + * + * Return : BLE RSSI value for advertising + */ + +int8_t bleutil_get_rssi(uint8_t *data, uint8_t len); + /* name: bleutil_get_advertising_flags * Get advertising flags from advertising data * This flags setting is defined in P.15 of @@ -291,4 +310,9 @@ int bleutil_get_manufacturer_specific_data(uint8_t *data, uint8_t **specific_data, uint8_t *specific_datalen); +#undef EXTERN +#ifdef __cplusplus +} +#endif + #endif /* __SDK_MODULES_INCLUDE_BLUETOOTH_BLE_UTIL_H */ diff --git a/sdk/modules/include/bluetooth/bluetooth.h b/sdk/modules/include/bluetooth/bluetooth.h index 28b867ceb..feecec0c9 100644 --- a/sdk/modules/include/bluetooth/bluetooth.h +++ b/sdk/modules/include/bluetooth/bluetooth.h @@ -254,16 +254,13 @@ typedef enum BT_VIS_DISCOVERY_CONNECTABLE = 3 /**< Discoverable and connectable */ } BT_VISIBILITY; -#ifdef EXTERNALS_NRF52 -#include "ble_types.h" -typedef int BLE_APPEARANCE -#else /** * @enum BLE_APPEARANCE * @brief BLE appearance ID */ typedef enum { + BLE_APPEARANCE_UNKNOWN = 0, BLE_APPEARANCE_GENERIC_PHONE = 64, BLE_APPEARANCE_GENERIC_COMPUTER = 128, BLE_APPEARANCE_GENERIC_WATCH = 192, @@ -304,7 +301,6 @@ typedef enum BLE_APPEARANCE_CYCLING_POWER_SENSOR = 1156, BLE_APPEARANCE_CYCLING_SPEED_AND_CADENCE_SENSOR = 1157, } BLE_APPEARANCE; -#endif /** * @enum BLE_GAP_IO_CAP diff --git a/sdk/modules/include/bluetooth/bt_common.h b/sdk/modules/include/bluetooth/bt_common.h index 126ac1de7..1f90fba77 100644 --- a/sdk/modules/include/bluetooth/bt_common.h +++ b/sdk/modules/include/bluetooth/bt_common.h @@ -1,7 +1,7 @@ /**************************************************************************** * modules/include/bluetooth/bt_common.h * - * Copyright 2018 Sony Semiconductor Solutions Corporation + * Copyright 2018, 2024 Sony Semiconductor Solutions Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -66,6 +66,17 @@ #define BLE_LTK_LEN (16) #define BLE_RAND_LEN (8) +/* Macro to convert time in msec for scan parameter */ + +#define BLE_SCAN_PARAM_INTERVAL_MSEC(t) ((t) * 1000 / 625) +#define BLE_SCAN_PARAM_WINDOW_MSEC(t) ((t) * 1000 / 625) +#define BLE_SCAN_PARAM_TIMEOUT_MSEC(t) ((t) * 1000 / 10000) + +/* Macro to convert time in msec for connection parameter */ + +#define BLE_CONN_PARAM_INTERVAL_MSEC(t) ((t) * 1000 / 1250) +#define BLE_CONN_PARAM_TIMEOUT_MSEC(t) ((t) * 1000 / 10000) + /** BLE status code */ /** Success */ @@ -140,6 +151,7 @@ struct bt_common_state_s struct ble_common_ops_s *ble_common_ops; /**< BLE status callbacks @ref ble_common_ops_s */ BT_ADDR bt_addr; /**< BT local device address @ref BT_ADDR */ BT_ADDR ble_addr; /**< BLE local device address @ref BT_ADDR */ + uint8_t ble_addr_type; /**< BLE local device address_type @ref BLE_GAP_ADDR_TYPES */ char bt_name[BT_NAME_LEN + 1]; /**< BT local device name */ char ble_name[BT_NAME_LEN + 1]; /**< BLE local device name */ }; @@ -215,6 +227,22 @@ struct ble_bondinfo_s struct ble_cccd_s *cccd; }; +struct ble_scan_param_s +{ + uint8_t active; /**< 1: active scan, 0: passive scan */ + uint16_t interval; /**< Scan interval in 625 us units. (2.5 - 10,240 ms) */ + uint16_t window; /**< Scan window in 625 us units. (2.5 - 10,240 ms) */ + uint16_t timeout; /**< Scan timeout in 10 ms units. 0: no timeout */ +}; + +struct ble_conn_param_s +{ + uint16_t min_interval; /**< Minimum Connection Interval in 1.25 ms units. (7.5 - 4,000 ms) */ + uint16_t max_interval; /**< Maximum Connection Interval in 1.25 ms units. (7.5 - 4,000 ms) */ + uint16_t slave_latency; /**< Slave Latency in number of connection events. (max 499) */ + uint16_t sup_timeout; /**< Connection Supervision Timeout in 10 ms unit. (100 - 32,000 ms) */ +}; + /** * @struct bt_common_ops_s * @brief Bluetooth Common application callbacks @@ -224,7 +252,7 @@ struct bt_common_ops_s void (*command_status)(BT_CMD_STATUS status); /**< Command status */ void (*pairing_complete)(BT_ADDR addr, BT_PAIR_STATUS status); /**< Pairing complete */ void (*inquiry_result)(BT_ADDR addr, char *name); /**< Inquiry data result */ - void (*inquiry_complete)(void); /**< Coplete inquiry */ + void (*inquiry_complete)(void); /**< Complete inquiry */ void (*connect_status_changed)(struct bt_acl_state_s *bt_acl_state, bool connected, int status); /**< Connection status change */ void (*connected_device_name)(const char *name); /**< Device name change */ void (*bond_info)(BT_ADDR addr); /**< Bonding information */ @@ -311,7 +339,7 @@ int bt_finalize(void); /** * @brief Set Bluetooth module address - * This is Spresense side address and should be call before bt_enable. + * This is Spresense side address and should be called before bt_enable. * * @param[in] addr: Bluetooth device address @ref BT_ADDR * @@ -332,7 +360,7 @@ int bt_get_address(BT_ADDR *addr); /** * @brief Set Bluetooth module name - * This name visible for other devices and should be call before bt_enable. + * This name visible for other devices and should be called before bt_enable. * * @param[in] name: Bluetooth device name * @@ -451,8 +479,8 @@ int bt_cancel_inquiry(void); int bt_register_common_cb(struct bt_common_ops_s *bt_common_ops); /** - * @brief Set Bluetooth LE module address - * This is Spresense side address and should be call before bt_enable. + * @brief Set Bluetooth LE module address of the random static address type. + * This is Spresense side address and should be called before bt_enable. * * @param[in] addr: Bluetooth LE device address @ref BT_ADDR * @@ -471,9 +499,28 @@ int ble_set_address(BT_ADDR *addr); int ble_get_address(BT_ADDR *addr); +/** + * @brief Set Bluetooth LE module address of the public address type. + * This is Spresense side address and should be called before bt_enable. + * + * @param[in] addr: Bluetooth LE device address @ref BT_ADDR + * + * @retval error code + */ + +int ble_set_public_address(BT_ADDR *addr); + +/** + * @brief Get Bluetooth LE module address type + * + * @retval Bluetooth LE device address type + */ + +uint8_t ble_get_address_type(void); + /** * @brief Set Bluetooth LE module name - * This name visible for other devices and should be call before bt_enable. + * This name visible for other devices and should be called before bt_enable. * * @param[in] name: Bluetooth LE device name * @@ -492,6 +539,16 @@ int ble_set_name(char *name); int ble_get_name(char *name); +/** + * @brief Set Bluetooth LE module appearance + * + * @param[in] appearance: Bluetooth LE device appearance + * + * @retval error code + */ + +int ble_set_appearance(BLE_APPEARANCE appearance); + /** * @brief Bluetooth LE enable * @@ -606,6 +663,39 @@ uint16_t ble_get_request_mtusize(void); int ble_get_negotiated_mtusize(uint16_t handle); +/** + * @brief Set Tx power + * + * @param[in] tx_power: Tx power [dBm] + * + * @note Set the value supported by each device. + * @note This API can be called after ble_enable. + * + * @retval BLE_SUCCESS or negated errno. + */ + +int ble_set_tx_power(int8_t tx_power); + +/** + * @brief Set scan parameter + * + * @param[in] param: scan parameter + * + * @retval error code + */ + +int ble_set_scan_param(struct ble_scan_param_s *param); + +/** + * @brief Set connection parameter + * + * @param[in] param: connection parameter + * + * @retval error code + */ + +int ble_set_conn_param(struct ble_conn_param_s *param); + /** * @brief Execute pairing * diff --git a/sdk/modules/include/bluetooth/hal/bt_event.h b/sdk/modules/include/bluetooth/hal/bt_event.h index 51792aa52..d7150ae58 100644 --- a/sdk/modules/include/bluetooth/hal/bt_event.h +++ b/sdk/modules/include/bluetooth/hal/bt_event.h @@ -1,7 +1,7 @@ /**************************************************************************** * modules/include/bluetooth/hal/bt_event.h * - * Copyright 2018, 2022 Sony Semiconductor Solutions Corporation + * Copyright 2018, 2022, 2024 Sony Semiconductor Solutions Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -72,11 +72,20 @@ #define BT_ADV_DATA_ADDRTYPE_LEN (1) /** @} */ +/** + *@name rssi length of advertise data + *@{ + */ +#define BT_ADV_DATA_RSSI_LEN (1) +/** @} */ + /** *@name Max ble advertise data length *@{ */ -#define BLE_MAX_ADV_DATA_LEN (BT_ADV_DATA_MAX_LEN + BT_ADV_DATA_ADDRTYPE_LEN) +#define BLE_MAX_ADV_DATA_LEN (BT_ADV_DATA_MAX_LEN + \ + BT_ADV_DATA_ADDRTYPE_LEN + \ + BT_ADV_DATA_RSSI_LEN) /** @} */ /** diff --git a/sdk/modules/include/bluetooth/hal/bt_if.h b/sdk/modules/include/bluetooth/hal/bt_if.h index 4595b58c4..f622a27c5 100644 --- a/sdk/modules/include/bluetooth/hal/bt_if.h +++ b/sdk/modules/include/bluetooth/hal/bt_if.h @@ -116,8 +116,8 @@ struct bt_hal_hfp_ops_s int (*connect)(BT_ADDR *addr, uint16_t handle, bool connect); /**< Connect/Disconnect HFP by BT_ADDR */ int (*audio_connect)(BT_ADDR *addr, uint16_t handle, bool connect); /**< Connect/Disconnect HFP audio by BT_ADDR */ int (*set_hf_feature)(BT_HFP_HF_FEATURE_FLAG hf_heature); /**< Setup HFP HF feature @ref BT_HFP_HF_FEATURE_FLAG */ - int (*send_at_command)(BT_ADDR *addr, char *at_str, uint16_t handle); /**< Send AT comand */ - int (*press_button)(BT_ADDR *addr, uint16_t handle); /**< Send pressing button comand */ + int (*send_at_command)(BT_ADDR *addr, char *at_str, uint16_t handle); /**< Send AT command */ + int (*press_button)(BT_ADDR *addr, uint16_t handle); /**< Send pressing button command */ }; /** @@ -137,7 +137,7 @@ struct bt_hal_spp_ops_s */ struct ble_hal_common_ops_s { - int (*setDevAddr)(BT_ADDR *addr); /**< Set BLE device address */ + int (*setDevAddr)(BT_ADDR *addr, uint8_t type); /**< Set BLE device address and type */ int (*setDevName)(char *name); /**< Set BLE device name */ int (*setAppearance)(BLE_APPEARANCE appearance); /**< Set BLE appearance ID @ref BLE_APPEARANCE */ int (*setPPCP)(BLE_CONN_PARAMS ppcp); /**< Set PPCP connection parameter */ @@ -150,6 +150,9 @@ struct ble_hal_common_ops_s uint16_t (*setMtuSize)(uint16_t sz); /**< Set MTU size */ uint16_t (*getMtuSize)(void); /**< Get MTU size */ int (*getNegotiatedMtuSize)(uint16_t handle); /**< Get negotiated MTU size */ + int (*setTxPower)(int8_t tx_power); /**< Set Tx Power */ + int (*setScanParam)(struct ble_scan_param_s *param); /**< Set scan parameter */ + int (*setConnParam)(struct ble_conn_param_s *param); /**< Set connection parameter */ }; /** @@ -212,6 +215,10 @@ struct ble_hal_gattc_ops_s int (*descriptor_read)(uint16_t conn_handle, uint16_t handle); + + /** Set vendor specific UUID */ + + int (*set_vendor_uuid)(BLE_UUID *uuid); }; /** diff --git a/sdk/modules/sensing/gnss/Make.defs b/sdk/modules/sensing/gnss/Make.defs index bedc1ea8e..dcea314d6 100644 --- a/sdk/modules/sensing/gnss/Make.defs +++ b/sdk/modules/sensing/gnss/Make.defs @@ -34,5 +34,5 @@ ############################################################################ ifeq ($(CONFIG_GPSUTILS_CXD5610NMEA_LIB),y) -CONFIGURED_APPS += sensing/gnss/cxd5610nmea +CONFIGURED_APPS += sensing/gnss endif diff --git a/sdk/modules/sensing/gnss/cxd5610nmea/Makefile b/sdk/modules/sensing/gnss/Makefile similarity index 90% rename from sdk/modules/sensing/gnss/cxd5610nmea/Makefile rename to sdk/modules/sensing/gnss/Makefile index a297ec268..d21e5b8f3 100644 --- a/sdk/modules/sensing/gnss/cxd5610nmea/Makefile +++ b/sdk/modules/sensing/gnss/Makefile @@ -1,7 +1,7 @@ ############################################################################ -# modules/sensing/gnss/cxd5610nmea/Makefile +# modules/sensing/gnss/Makefile # -# Copyright 2023 Sony Semiconductor Solutions Corporation +# Copyright 2024 Sony Semiconductor Solutions Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -34,6 +34,12 @@ ############################################################################ -include $(SDKDIR)/modules/Make.defs + +ifeq ($(CONFIG_GPSUTILS_CXD5610NMEA_LIB),y) MODNAME = cxd5610nmea +VPATH = cxd5610nmea +DEPPATH = --dep-path cxd5610nmea CSRCS = gnss_nmea.c +endif + include $(SDKDIR)/modules/Module.mk diff --git a/sdk/modules/sensing/tap/tap_manager.cpp b/sdk/modules/sensing/tap/tap_manager.cpp index 7209ec3bc..68c000e10 100644 --- a/sdk/modules/sensing/tap/tap_manager.cpp +++ b/sdk/modules/sensing/tap/tap_manager.cpp @@ -163,12 +163,8 @@ static int TapMngsendAcccmd(int acc_cmd) /* send signal */ -#ifdef CONFIG_CAN_PASS_STRUCTS value.sival_ptr = NULL; (void)sigqueue(g_tap_mng_task_id, TAP_MNG_CMD_SIGNAL, value); -#else - (void)sigqueue(g_tap_mng_task_id, TAP_MNG_CMD_SIGNAL, NULL); -#endif } /* waiting for command complete */ @@ -279,7 +275,7 @@ static void TapMngTapLibRun(void) timeout.tv_sec = 2; timeout.tv_nsec = 0; - /* send responce ACC_INIT complete */ + /* send response ACC_INIT complete */ TapMngsendAcccmdResp(); @@ -784,7 +780,7 @@ int TapMngStop(int ctl_id) TAP_MNG_NODE_LOCK(); - /* Find Node from contol id */ + /* Find Node from control id */ p_tapmng_node = TapMngFindNode(ctl_id); if (NULL != p_tapmng_node) diff --git a/sdk/system/logdump/logdump.c b/sdk/system/logdump/logdump.c index ad862dd07..cf88d91b7 100644 --- a/sdk/system/logdump/logdump.c +++ b/sdk/system/logdump/logdump.c @@ -111,7 +111,7 @@ int logdump_main(int argc, char **argv) /* Dump from file */ - snprintf(logfile, 64, CONFIG_SYSTEM_LOGSAVE_MOUNTPOINT"/%s.log", name); + snprintf(logfile, 64, CONFIG_SYSTEM_LOGDUMP_MOUNTPOINT"/%s.log", name); fp = fopen(logfile, "rb"); if (fp == NULL) diff --git a/sdk/system/lte_sysctl/Makefile b/sdk/system/lte_sysctl/Makefile index 60c3a4485..1813248eb 100644 --- a/sdk/system/lte_sysctl/Makefile +++ b/sdk/system/lte_sysctl/Makefile @@ -36,11 +36,6 @@ include $(APPDIR)/Make.defs include $(SDKDIR)/Make.defs -LTEALTCOMAPIINCDIR = $(SDKDIR)$(DELIM)modules$(DELIM)include$(DELIM)lte - -CFLAGS += -I$(LTEALTCOMAPIINCDIR)$(DELIM)altcom -CFLAGS += -I$(LTEALTCOMAPIINCDIR)$(DELIM)altcom$(DELIM)net - MAINSRC = lte_sysctl.c PROGNAME = $(CONFIG_LTE_SYSCTL_CMDNAME) diff --git a/sdk/system/lte_sysctl/lte_sysctl.c b/sdk/system/lte_sysctl/lte_sysctl.c index 874471ab3..3723520c5 100644 --- a/sdk/system/lte_sysctl/lte_sysctl.c +++ b/sdk/system/lte_sysctl/lte_sysctl.c @@ -133,7 +133,7 @@ #define CATM1_STR "CAT-M1" #define MATCH_STRING(str1, str2) ((strlen(str1) == strlen(str2)) && \ - (strncmp(str1, str2, strlen(str2)) == 0)) + (strncasecmp(str1, str2, strlen(str2)) == 0)) /**************************************************************************** * Private Data @@ -167,9 +167,10 @@ static void show_usage(FAR const char *progname, int exitcode) " [-u ] [-p ] [-r ]" " start\n"); fprintf(stderr, " -a: APN name\n"); - fprintf(stderr, " -i: IP type 0=IPv4, 1=IPv6, 2=IPv4 and IPv6," - " 3=Non-IP\n"); - fprintf(stderr, " -v: Authenticaion type 0=NONE, 1=PAP, 2=CHAP\n"); + fprintf(stderr, " -i: IP type \"V4\", \"V6\", \"V4V6\", \"NON\" or" + " 0=IPv4, 1=IPv6, 2=IPv4 and IPv6, 3=Non-IP\n"); + fprintf(stderr, " -v: Authenticaion type \"NONE\", \"PAP\", \"CHAP\", or" + " 0=NONE, 1=PAP, 2=CHAP\n"); fprintf(stderr, " -u: User name for authenticaion\n"); fprintf(stderr, " -p: Password for authenticaion\n"); fprintf(stderr, " -r: Radio Access Technology type M1=CAT-M1," @@ -945,27 +946,61 @@ int main(int argc, FAR char *argv[]) setting_apn.apn_type = (uint32_t)apn_type; break; case 'i': - ip_type = strtol(optarg, NULL, LTE_SYSCTL_STRTOL_BASE); - if ((ip_type != LTE_IPTYPE_V4) && - (ip_type != LTE_IPTYPE_V6) && - (ip_type != LTE_IPTYPE_V4V6) && - (ip_type != LTE_IPTYPE_NON)) + if (MATCH_STRING(optarg, "V4")) { - fprintf(stderr, "Invalid IP type:%ld\n", ip_type); - show_usage(argv[0], EXIT_FAILURE); + ip_type = LTE_IPTYPE_V4; + } + else if (MATCH_STRING(optarg, "V6")) + { + ip_type = LTE_IPTYPE_V6; + } + else if (MATCH_STRING(optarg, "V4V6")) + { + ip_type = LTE_IPTYPE_V4V6; + } + else if (MATCH_STRING(optarg, "NON")) + { + ip_type = LTE_IPTYPE_NON; + } + else + { + if (optarg[1] == '\0' && (optarg[0] >= '0' && optarg[0] <= '3')) + { + ip_type = atoi(optarg); + } + else + { + fprintf(stderr, "Invalid IP type: %s\n", optarg); + show_usage(argv[0], EXIT_FAILURE); + } } setting_apn.ip_type = (uint8_t)ip_type; break; case 'v': - auth_type = strtol(optarg, NULL, LTE_SYSCTL_STRTOL_BASE); - if ((auth_type != LTE_APN_AUTHTYPE_NONE) && - (auth_type != LTE_APN_AUTHTYPE_PAP) && - (auth_type != LTE_APN_AUTHTYPE_CHAP)) + if (MATCH_STRING(optarg, "NONE")) { - fprintf(stderr, "Invalid authenticaion type:%ld\n", - auth_type); - show_usage(argv[0], EXIT_FAILURE); + auth_type = LTE_APN_AUTHTYPE_NONE; + } + else if (MATCH_STRING(optarg, "PAP")) + { + auth_type = LTE_APN_AUTHTYPE_PAP; + } + else if (MATCH_STRING(optarg, "CHAP")) + { + auth_type = LTE_APN_AUTHTYPE_CHAP; + } + else + { + if (optarg[1] == '\0' && (optarg[0] >= '0' && optarg[0] <= '2')) + { + auth_type = atoi(optarg); + } + else + { + fprintf(stderr, "Invalid authenticaion type: %s\n", optarg); + show_usage(argv[0], EXIT_FAILURE); + } } setting_apn.auth_type = (uint8_t)auth_type; diff --git a/sdk/tools/Board.mk b/sdk/tools/Board.mk deleted file mode 100644 index 544583b2f..000000000 --- a/sdk/tools/Board.mk +++ /dev/null @@ -1,123 +0,0 @@ -############################################################################ -# bsp/scripts/Board.mk -# -# Copyright (C) 2015 Gregory Nutt. All rights reserved. -# Copyright (C) 2015 Omni Hoverboards Inc. All rights reserved. -# Author: Gregory Nutt -# Paul Alexander Patience -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - --include $(TOPDIR)/Make.defs --include $(SDKDIR)/Make.defs - -AOBJS = $(ASRCS:.S=$(OBJEXT)) -COBJS = $(CSRCS:.c=$(OBJEXT)) -CXXOBJS = $(CXXSRCS:.cxx=$(OBJEXT)) - -SRCS = $(ASRCS) $(CSRCS) -OBJS = $(AOBJS) $(COBJS) - -SCHEDSRCDIR = $(TOPDIR)$(DELIM)sched -ARCHSRCDIR = $(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src -BSPSRCDIR = $(SDKDIR)$(DELIM)bsp$(DELIM)src - -ifneq ($(CONFIG_ARCH_FAMILY),) - ARCH_FAMILY = $(patsubst "%",%,$(CONFIG_ARCH_FAMILY)) -endif - -ifeq ($(WINTOOL),y) - CFLAGS += -I "${shell cygpath -w $(SCHEDSRCDIR)}" - CFLAGS += -I "${shell cygpath -w $(ARCHSRCDIR)$(DELIM)chip}" - CFLAGS += -I "${shell cygpath -w $(ARCHSRCDIR)$(DELIM)common}" -ifneq ($(ARCH_FAMILY),) - CFLAGS += -I "${shell cygpath -w $(ARCHSRCDIR)$(DELIM)$(ARCH_FAMILY)}" -endif - CFLAGS += -I "${shell cygpath -w $(BSPSRCDIR)}" -else - CFLAGS += -I$(SCHEDSRCDIR) - CFLAGS += -I$(ARCHSRCDIR)$(DELIM)chip - CFLAGS += -I$(ARCHSRCDIR)$(DELIM)common -ifneq ($(ARCH_FAMILY),) - CFLAGS += -I$(ARCHSRCDIR)$(DELIM)$(ARCH_FAMILY) -endif - CFLAGS += -I$(BSPSRCDIR) -endif - -all: libboard$(LIBEXT) - -$(ASRCS) $(HEAD_ASRC): %$(ASMEXT): %.S -ifeq ($(WINTOOL),y) - $(Q) $(CPP) $(CPPFLAGS) `cygpath -w $<` -o $@.tmp -else - $(Q) $(CPP) $(CPPFLAGS) $< -o $@.tmp -endif - $(Q) cat $@.tmp | sed -e "s/^#/;/g" > $@ - $(Q) rm $@.tmp - -$(AOBJS): %$(OBJEXT): %$(ASMEXT) - $(call ASSEMBLE, $<, $@) - -$(COBJS) $(LINKOBJS): %$(OBJEXT): %.c - $(call COMPILE, $<, $@) - -$(CXXOBJS) $(LINKOBJS): %$(OBJEXT): %.cxx - $(call COMPILEXX, $<, $@) - -libboard$(LIBEXT): $(OBJS) $(CXXOBJS) - $(Q) $(AR) $@ -ifneq ($(OBJS),) - $(call ARCHIVE, $@, $(OBJS) $(CXXOBJS)) -endif - -.depend: Makefile $(SRCS) $(CXXSRCS) - $(Q) $(MKDEP) $(DEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep -ifneq ($(CXXSRCS),) - $(Q) $(MKDEP) $(DEPPATH) "$(CXX)" -- $(CXXFLAGS) -- $(CXXSRCS) >>Make.dep -endif - $(Q) touch $@ - -depend: .depend - -ifneq ($(BOARD_CONTEXT),y) -context: -endif - -clean: - $(call DELFILE, libboard$(LIBEXT)) - $(call CLEAN) - $(EXTRA_CLEAN) - -distclean: clean - $(call DELFILE, Make.dep) - $(call DELFILE, .depend) - $(EXTRA_DISTCLEAN) - --include Make.dep diff --git a/sdk/tools/Makefile.export b/sdk/tools/Makefile.export deleted file mode 100644 index d13b27558..000000000 --- a/sdk/tools/Makefile.export +++ /dev/null @@ -1,103 +0,0 @@ -############################################################################ -# Makefile.export -# -# Copyright (C) 2011, 2014 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################ - -include $(TOPDIR)/.config -include $(EXPORTDIR)/Make.defs - -ifdef ARCHSCRIPT - -# ARCHSCRIPT may contain a leading -T; it must not be followed by a space -# for this to work. - -ifeq ($(WINTOOL),y) -LDPATH = $(shell cygpath -u $(patsubst -T%,%,$(ARCHSCRIPT))) -else -LDPATH = $(patsubst -T%,%,$(ARCHSCRIPT)) -endif - -LDNAME = ${notdir ${LDPATH}} -LDDIR = ${dir ${LDPATH}} -endif - -ARCHSUBDIR = "arch/$(CONFIG_ARCH)/src" -ARCHDIR ="$(TOPDIR)/$(ARCHSUBDIR)" - -all: $(EXPORTDIR)/makeinfo.sh -default: all -.PHONY: clean - -$(EXPORTDIR)/makeinfo.sh: $(TOPDIR)/.config $(EXPORTDIR)/Make.defs - @echo "#!/usr/bin/env bash" > $(EXPORTDIR)/makeinfo.sh - @echo "" >> $(EXPORTDIR)/makeinfo.sh - @echo "ARCHSUBDIR=\"$(ARCHSUBDIR)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "ARCHDIR=\"$(ARCHDIR)\"" >> $(EXPORTDIR)/makeinfo.sh -ifdef ARCHSCRIPT - @echo "LDNAME=\"$(LDNAME)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "LDDIR=\"$(LDDIR)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "LDPATH=\"$(LDPATH)\"" >> $(EXPORTDIR)/makeinfo.sh -endif - @echo "ARCHCFLAGS=\"$(ARCHCFLAGS) $(ARCHCPUFLAGS)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "ARCHCXXFLAGS=\"$(ARCHCXXFLAGS) $(ARCHCPUFLAGS)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "ARCHPICFLAGS=\"$(ARCHPICFLAGS)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "ARCHWARNINGS=\"$(ARCHWARNINGS)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "ARCHWARNINGSXX=\"$(ARCHWARNINGSXX)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "ARCHOPTIMIZATION=\"$(ARCHOPTIMIZATION)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "WINTOOL=\"$(WINTOOL)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "CROSSDEV=\"$(CROSSDEV)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "CC=\"$(CC)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "CXX=\"$(CXX)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "CPP=\"$(CPP)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "LD=\"$(LD)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "AR=\"$(AR)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "NM=\"$(NM)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "OBJCOPY=\"$(OBJCOPY)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "OBJDUMP=\"$(OBJDUMP)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "NXFLATLDFLAGS1=\"$(NXFLATLDFLAGS1)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "NXFLATLDFLAGS2=\"$(NXFLATLDFLAGS2)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "OBJEXT=\"$(OBJEXT)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "LIBEXT=\"$(LIBEXT)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "EXEEXT=\"$(EXEEXT)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "HOSTCC=\"$(HOSTCC)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "HOSTINCLUDES=\"$(HOSTINCLUDES)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "HOSTCFLAGS=\"$(HOSTCFLAGS)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "HOSTLDFLAGS=\"$(HOSTLDFLAGS)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "HOSTEXEEXT=\"$(HOSTEXEEXT)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "DIRLINK=\"$(DIRLINK)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "DIRUNLINK=\"$(DIRUNLINK)\"" >> $(EXPORTDIR)/makeinfo.sh - @echo "MKDEP=\"$(MKDEP)\"" >> $(EXPORTDIR)/makeinfo.sh - $(Q) chmod 755 $(EXPORTDIR)/makeinfo.sh - -clean: - $(Q) rm -f $(EXPORTDIR)/makeinfo.sh diff --git a/sdk/tools/bin/mkalwcomp.py b/sdk/tools/bin/mkalwcomp.py new file mode 100755 index 000000000..673aa548e --- /dev/null +++ b/sdk/tools/bin/mkalwcomp.py @@ -0,0 +1,1039 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +############################################################################ +# tools/bin/mkalwcomp.py +# +# Copyright 2024 Sony Semiconductor Solutions Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name of Sony Semiconductor Solutions Corporation nor +# the names of its contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +import os +import sys +import re +import shutil + +############################################################################ +### This tool's description + +TOOL_DESCRIPTION = ''' +Generate a new audiolite worker component and worker sckelton code +''' + +EPILOG = '''Generate a audiolite component class in specified directory +with worker sckelton code stored in a sub directory created by this tool. +''' + +############################################################################ +### Command line options + +WORKER_OPT_STRT = 's' +WORKER_OPT_STOP = 'x' +WORKER_OPT_INFO = 'i' +WORKER_OPT_PAUS = 'p' +WORKER_OPT_GAIN = 'g' +WORKER_OPT_USER = 'u' +WORKER_OPT_DEBG = 'd' +WORKER_OPT_DEFT = 'f' +WORKER_OPT_IMEM = 'm' +WORKER_OPT_OMEM = 'o' +WORKER_OPTS = WORKER_OPT_STRT + WORKER_OPT_STOP + WORKER_OPT_INFO + \ + WORKER_OPT_PAUS + WORKER_OPT_GAIN + WORKER_OPT_USER + \ + WORKER_OPT_DEBG + WORKER_OPT_DEFT + WORKER_OPT_IMEM + \ + WORKER_OPT_OMEM + +worker_opt_help = \ +'''Worker code options, choose one or more in ''' + str(list(WORKER_OPTS)) + ''' + ''' + WORKER_OPT_STRT + ''' : enable starting state support + ''' + WORKER_OPT_STOP + ''' : enable stopping state support + ''' + WORKER_OPT_INFO + ''' : enable system information support + ''' + WORKER_OPT_PAUS + ''' : enable pause support + ''' + WORKER_OPT_GAIN + ''' : enable gain message support + ''' + WORKER_OPT_USER + ''' : enable user original message handle + ''' + WORKER_OPT_DEBG + ''' : enable debug message handle + ''' + WORKER_OPT_DEFT + ''' : enable start/stop/term message handle + ''' + WORKER_OPT_IMEM + ''' : enable input memory injection message handle + ''' + WORKER_OPT_OMEM + ''' : enable output memory injection message handle + +''' + +COMP_OPT_ERRO = 'e' +COMP_OPT_INFO = 'i' +COMP_OPT_DONE = 'f' +COMP_OPT_TERM = 't' +COMP_OPT_IMEM = 'm' +COMP_OPT_OMEM = 'o' +COMP_OPT_USER = 'u' +COMP_OPT_DEBG = 'd' +COMP_OPTS = COMP_OPT_ERRO + COMP_OPT_INFO + COMP_OPT_DONE + COMP_OPT_TERM + \ + COMP_OPT_IMEM + COMP_OPT_OMEM + COMP_OPT_USER + COMP_OPT_DEBG + +comp_opt_help = \ +'''Component code options, choose one or more in ''' + str(list(COMP_OPTS)) + ''' + ''' + COMP_OPT_ERRO + ''' : handle error message + ''' + COMP_OPT_INFO + ''' : handle information message + ''' + COMP_OPT_DONE + ''' : handle done message + ''' + COMP_OPT_TERM + ''' : handle term message + ''' + COMP_OPT_IMEM + ''' : handle release input mem message + ''' + COMP_OPT_OMEM + ''' : handle release output mem message + ''' + COMP_OPT_USER + ''' : handle user original message + ''' + COMP_OPT_DEBG + ''' : handle debug message + +''' + +############################################################################ +### Worker gitignore + +WORKER_GITIGNORE_TEMPLATE = \ +'''{workername} +*.elf +*.spk +''' + +############################################################################ +### Worker Configuration File Template + +WORKER_CONFIG_TEMPLATE = \ +'''#ifndef __AUDIOLITE_WORKER_COMMON_ALWORKER_COMMFW_CONFIG_H +#define __AUDIOLITE_WORKER_COMMON_ALWORKER_COMMFW_CONFIG_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/** Definition of NOTUSE_XXXXXX + * + * If you want to handle messages below, + * comment out to enable it. + */ + +{nouse_strt} +{nouse_stop} +{nouse_paus} +{nouse_gain} +{nouse_user} +{nouse_debg} + +/** Definition of Memory block QUEUE size + * + * Input side memory block size will defined as CONF_WORKER_IMEMMAX. + * Output side memory block size will defined as CONF_WORKER_OMEMMAX. + */ + +#define CONF_WORKER_IMEMMAX ({imem}) +#define CONF_WORKER_OMEMMAX ({omem}) + +#endif /* __AUDIOLITE_WORKER_COMMON_ALWORKER_COMMFW_CONFIG_H */ +''' + +CONFIG_DEF_GAIN = '#define NOTUSE_INSTGAIN' +CONFIG_DEF_USER = '#define NOTUSE_ORGMSG' +CONFIG_DEF_STRT = '#define NOTUSE_STARTING' +CONFIG_DEF_STOP = '#define NOTUSE_STOPPING' +CONFIG_DEF_DEBG = '#define NOTUSE_SYSDBG' +CONFIG_DEF_INFO = '#define NOTUSE_SYSPARAM' +CONFIG_DEF_PAUS = '#define NOTUSE_SYSPAUSE' + +############################################################################ +### Worker Header File Template + +WORKER_MAIN_HEADER = '''#ifndef __AUDIOLITE_WORKER_USR_{nameupper}_H +#define __AUDIOLITE_WORKER_USR_{nameupper}_H + +/* Add a common definition between worker and the audiolite component here */ + +#define {nameupper}_WORKER_VERSION (1) + +#endif /* __AUDIOLITE_WORKER_USR_{nameupper}_H */ +''' + +############################################################################ +### Worker Source File Template + +WORKER_MAIN_SRC = '''/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include "{workername}_worker_main.h" + +/**************************************************************************** + * Private Data Types + ****************************************************************************/ + +struct my_worker_instance_s +{{ + /* ALWORKERCOMMFW_INSTANCE should be on top of your instance */ + + ALWORKERCOMMFW_INSTANCE; + + /* Add specific items for your application here */ +}}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct my_worker_instance_s g_instance; +static memblk_t *imem_inuse = NULL; +static memblk_t *omem_inuse = NULL; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/* on_process(): + * This is called when the state is in PROCESS. + * + * Return code controls state change. + * AL_COMMFW_RET_OK : Stay the state to process next work. + * AL_COMMFW_RET_NOIMEM : Change to WAIT_IMEM for waiting next input. + * AL_COMMFW_RET_NOOMEM : Change to WAIT_OMEM for waiting next output. + */ + +static int on_process(void *arg) +{{ + struct my_worker_instance_s *inst = + (struct my_worker_instance_s *)arg; + + /* Add your original code here. + * This sckelton code implements just copy input memory to output memory. */ + + /* If no memory, get new memory block from queue */ + + if (imem_inuse == NULL) + {{ + imem_inuse = TAKE_IMEM(inst); + }} + + if (omem_inuse == NULL) + {{ + omem_inuse = TAKE_OMEM(inst); + }} + + /* Copy data from input memory to output memory */ + + if (imem_inuse && omem_inuse) + {{ + memblk_fillup(omem_inuse, imem_inuse); + }} + + /* Release IMEM if all data is used */ + + if (imem_inuse && memblk_is_empty(imem_inuse)) + {{ + FREE_MEMBLK(imem_inuse, inst); + imem_inuse = NULL; + }} + + /* Release OMEM if it is filled up */ + + if (omem_inuse && memblk_is_full(omem_inuse)) + {{ + FREE_MEMBLK(omem_inuse, inst); + omem_inuse = NULL; + }} + + return AL_COMMFW_RET_OK; +}} + +{on_gain}{on_user}{on_debg}{on_paus}''' + \ +'''{on_omem}{on_imem}{on_info}''' + \ +'''{on_stop}{on_strt}{on_term}''' + \ +'''{on_stpm}{on_play}''' + \ +'''/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(void) +{{ + alcommfw_cbs_t *cbs = alworker_commfw_get_cbtable(); + + if (alworker_commfw_initialize((alworker_insthead_t *)&g_instance) != OK) + {{ + return 0; + }} + + /* Set callbacks to handle host message and + * state processing + */ + + SET_PROCESS(cbs, on_process); +{set_play}{set_stop}{set_term}{set_strt}{set_sping}{set_info}{set_imem}{set_omem}{set_paus}{set_debg}{set_user}{set_gain} + /* Send boot message to host to notice this worker is ready */ + + alworker_send_bootmsg({nameupper}_WORKER_VERSION, NULL); + + /* Start message loop. + * This function returns receive SYSTERM message from a host. + */ + + alworker_commfw_msgloop((alworker_insthead_t *)&g_instance); + + return 0; +}} +''' + +SET_PLAYMSG = ' SET_PLAYMSG(cbs, on_playmsg);\n' +SET_STOPMSG = ' SET_STOPMSG(cbs, on_stopmsg);\n' +SET_TERMMSG = ' SET_TERMMSG(cbs, on_termmsg);\n' +SET_STARTING = ' SET_STARTING(cbs, on_starting);\n' +SET_STOPPING = ' SET_STOPPING(cbs, on_stopping);\n' +SET_PARAM = ' SET_PARAMMSG(cbs, on_parammsg);\n' +SET_IMEM = ' SET_IMEMINJECT(cbs, on_imeminject);\n' +SET_OMEM = ' SET_OMEMINJECT(cbs, on_omeminject);\n' +SET_PAUSE = ' SET_PAUSEMSG(cbs, on_pausemsg);\n' + \ + ' SET_PAUSING(cbs, on_pausing);\n' +SET_DBGMSG = ' SET_DBGMSG(cbs, on_dbgmsg);\n' +SET_USRMSG = ' SET_USRMSG(cbs, on_usrmsg);\n' +SET_GAIN = ' SET_GAINMSG(cbs, on_gainmsg);\n' + +ON_PLAYF = '''/* on_playmsg(): + * This is called when AL_COMM_MSGCODESYS_PLAY is received from a host. + * + * Return AL_COMMFW_RET_OK, to go to STARTING state, + * Non AL_COMMFW_RET_OK makes return a message with a returned code + * to the host. + */ + +static int on_playmsg(int state, void *arg) +{ + /* + struct my_worker_instance_s *inst = + (struct my_worker_instance_s *)arg; + */ + + /* Add your code here */ + + return AL_COMMFW_RET_OK; +} + +''' + +ON_STPMF = '''/* on_stopmsg(): + * This is called when AL_COMM_MSGCODESYS_STOP is received from a host. + * After return from this function, state will go to STOPPING. + */ + +static void on_stopmsg(int state, void *arg) +{ + /* + struct my_worker_instance_s *inst = + (struct my_worker_instance_s *)arg; + */ + + /* Add your code here */ +} + +''' + +ON_TERMF = '''/* on_termmsg(): + * This is called when AL_COMM_MSGCODESYS_TERM is received from a host. + * After return from this function, this worker will be destroied. + */ + +static void on_termmsg(void *arg, + al_comm_msghdr_t hdr, + al_comm_msgopt_t *opt) +{ + struct my_worker_instance_s *inst = + (struct my_worker_instance_s *)arg; + + /* Add your code here */ +} + +''' + +ON_STARTF = '''/* on_starting(): + * This is called when the state is in STARTING. + * + * This callback is for preparing for processing. + * Return AL_COMMFW_RET_OK to go to PROCESS state, + * other return code makes the state stay. + */ + +static int on_starting(void *arg) +{ + struct my_worker_instance_s *inst = + (struct my_worker_instance_s *)arg; + + /* Add your code here */ + + return AL_COMMFW_RET_OK; +} + +''' + +ON_STOPF = '''/* on_stopping(): + * This is called when the state is in STOPPING. + * + * Return code controls state change. + * AL_COMMFW_RET_OK : Change to STOPPED. (Complete stopping process) + * AL_COMMFW_RET_NOIMEM : Change to WAIT_IMEM for waiting next input. + * AL_COMMFW_RET_NOOMEM : Change to WAIT_OMEM for waiting next output. + * AL_COMMFW_RET_STAY : Stay the state to continue stopping process. + */ + +static int on_stopping(void *arg) +{ + struct my_worker_instance_s *inst = + (struct my_worker_instance_s *)arg; + + /* Add your code here */ + + return AL_COMMFW_RET_OK; +} + +''' + +ON_INFOF = '''/* on_parammsg(): + * This is called when AL_COMM_MSGCODESYS_PARAM is received from a host. + * + * If this returns not AL_COMMFW_RET_OK, the ret code will send to + * the host as error code. + */ + +static int on_parammsg(int state, void *arg, + al_comm_msghdr_t hdr, al_comm_msgopt_t *opt) +{ + struct my_worker_instance_s *inst = + (struct my_worker_instance_s *)arg; + + /* Add your code here */ + + return AL_COMMFW_RET_OK; +} + +''' + +############################################################################ +### Worker Memory Injection callbask code + +ON_IMEMF = '''/* on_imeminject(): + * This is called when AL_COMM_MESSAGE_FMEM is received from a host. + * + * Return AL_COMMFW_RET_OK makes state forward + */ + +static int on_imeminject(int state, void *arg) +{ + struct my_worker_instance_s *inst = + (struct my_worker_instance_s *)arg; + + /* Add your code here */ + + return AL_COMMFW_RET_OK; +} + +''' + +ON_OMEMF = '''/* on_omeminject(): + * This is called when AL_COMM_MESSAGE_OMEM is received from a host. + * + * Return AL_COMMFW_RET_OK makes state forward + */ + +static int on_omeminject(int state, void *arg) +{ + struct my_worker_instance_s *inst = + (struct my_worker_instance_s *)arg; + + /* Add your code here */ + + return AL_COMMFW_RET_OK; +} + +''' + +############################################################################ +### Worker Optional message handdler template + +ON_PAUSF = '''/* on_pausemsg(): + * This is called when AL_COMM_MSGCODESYS_PAUSE is received from a host. + * + * Return AL_COMMFW_RET_OK, to go to PAUSING state, + * Non AL_COMMFW_RET_OK makes return a message with a returned code + * to the host. + */ + +static int on_pausemsg(int state, void *arg) +{ + struct my_worker_instance_s *inst = + (struct my_worker_instance_s *)arg; + + /* Add your code here */ + + return AL_COMMFW_RET_OK; +} + +/* on_pausing(): + * This is called when the state is in PAUSING. + * + * Return code controls state change. + * AL_COMMFW_RET_OK : Change to STOPPED. (Complete pausing process) + * AL_COMMFW_RET_NOIMEM : Change to WAIT_IMEM for waiting next input. + * AL_COMMFW_RET_NOOMEM : Change to WAIT_OMEM for waiting next output. + * AL_COMMFW_RET_STAY : Stay the state to continue stopping process. + */ + +static int on_pausing(void *arg) +{ + struct my_worker_instance_s *inst = + (struct my_worker_instance_s *)arg; + + /* Add your code here */ + + return AL_COMMFW_RET_OK; +} + +''' + +ON_DEBGF = '''/* on_dbgmsg(): + * This is called when AL_COMM_MSGCODESYS_DBG is received from a host. + * + * If this returns not AL_COMMFW_RET_OK, the ret code will send to + * the host as error code. + */ + +static int on_dbgmsg(int state, void *arg, + al_comm_msghdr_t hdr, al_comm_msgopt_t *opt) +{ + struct my_worker_instance_s *inst = + (struct my_worker_instance_s *)arg; + + /* Add your code here */ + + return AL_COMMFW_RET_OK; +} + +''' + +ON_USERF = '''/* on_usrmsg(): + * This is called when not standard message id is received from a host. + * + * If this returns not AL_COMMFW_RET_OK, the ret code will send to + * the host as error code. + */ + +static int on_usrmsg(int state, void *arg, + al_comm_msghdr_t hdr, al_comm_msgopt_t *opt) +{ + struct my_worker_instance_s *inst = + (struct my_worker_instance_s *)arg; + + /* Add your code here */ + + return AL_COMMFW_RET_OK; +} + +''' + +ON_GAINF = '''/* on_gainmsg(): + * This is called when AL_COMM_MSGCODEINST_GAIN is received from a host. + * + * If this returns not AL_COMMFW_RET_OK, the ret code will send to + * the host as error code. + */ + +static int on_gainmsg(int state, void *arg, float gain) +{ + struct my_worker_instance_s *inst = + (struct my_worker_instance_s *)arg; + + /* Add your code here */ + + return AL_COMMFW_RET_OK; +} + +''' + +############################################################################ +### Worker Makefile Template + +MAKEFILE_TEMPLATE = '''include $(APPDIR)/Make.defs +-include $(SDKDIR)/Make.defs + +ALWORKER_COMMON = $(SDKDIR)/modules/audiolite/worker/common + +BUILD_EXECUTE = 1 + +# ALWORKER_USE_CMSIS = 1 +# ALWORKER_USE_RESAMPLER = 1 + +BIN = {workername} +SPK = $(BIN).spk + +CSRCS = {workername}_worker_main.c + +CFLAGS += +LDLIBPATH = +LDLIBS = + +VPASH_DIRS = + +INCDIRS = + +include $(ALWORKER_COMMON)/mkfiles/alworker.mk +''' + +############################################################################ +### Template Audiolite component for this worker (header) + +COMPONENT_HEADER_TEMPLATE = '''#ifndef __INCLUDE_AUDIOLITE_USER_{nameupper}_H +#define __INCLUDE_AUDIOLITE_USER_{nameupper}_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include <{workername}/{workername}_worker_main.h> + +/**************************************************************************** + * Class Definitions + ****************************************************************************/ + +class alusr_{workername} : public audiolite_workercomp +{{ + protected: + class {workername}_msglistener : public audiolite_stdworker_msglistener + {{ + public: + virtual ~{workername}_msglistener(){{}}; + void bootup(audiolite_workercomp *wcomp, al_wtask_t *wtask, + int version, void *d);''' + \ +'''{cp_erro}{cp_debg}{cp_info}{cp_done}{cp_term}{cp_imem}{cp_omem}{cp_user} + }}; + + {workername}_msglistener _msglsnr; + audiolite_mempoolapbuf *_outmempool; + + public: + alusr_{workername}(); + virtual ~alusr_{workername}(); +}}; + +#endif /* __INCLUDE_AUDIOLITE_USER_{nameupper}_H */ +''' + +CP_ERROM = ''' + void error(audiolite_workercomp *wcomp, al_wtask_t *wtask, + int id, int ercode); +''' + +CP_DEBGM = ''' + void debug(audiolite_workercomp *wcomp, al_wtask_t *wtask, int code); +''' + +CP_INFOM = ''' + void info(audiolite_workercomp *wcomp, al_wtask_t *wtask, + int id, int chs, int fs, int layer, int rate); +''' + +CP_DONEM = ''' + void done(audiolite_workercomp *wcomp, al_wtask_t *wtask, int id); +''' + +CP_TERMM = ''' + void term(audiolite_workercomp *wcomp); +''' + +CP_IMEMM = ''' + audiolite_memapbuf *release_inmem(audiolite_workercomp *wcomp, + al_wtask_t *wtask, + audiolite_memapbuf *mem, int size); +''' + +CP_OMEMM = ''' + audiolite_memapbuf *release_outmem(audiolite_workercomp *wcomp, + al_wtask_t *wtask, + audiolite_memapbuf *mem); +''' + +CP_USERM = ''' + void usermsg(audiolite_workercomp *wcomp, al_wtask_t *wtask, + al_comm_msghdr_t hdr, al_comm_msgopt_t *opt); +''' + +INIT_OUTMEMPOOL = ''' _outmempool = new audiolite_mempoolapbuf; + _outmempool->create_instance(4096, 8); + set_mempool(_outmempool); +''' + +COMPONENT_CXX_TEMPLATE = '''#include +#include + +/**************************************************************************** + * alusr_{workername} Class Methods + ****************************************************************************/ + +alusr_{workername}::alusr_{workername}() : + audiolite_workercomp("{workername}", {imem}, {omem}), _outmempool(NULL) +{{ + set_msglistener(&_msglsnr); +{init_outmempool}}} + +alusr_{workername}::~alusr_{workername}() +{{ + set_mempool(NULL); + if (_outmempool) + delete _outmempool; +}} + +/**************************************************************************** + * Message Listener Class Methods + ****************************************************************************/ + +void alusr_{workername}::{workername}_msglistener::bootup( + audiolite_workercomp *wcomp, al_wtask_t *wtask, int version, void *d) +{{ + // This method is called just after receiving boot-up + // message from the worker + + if (version == {nameupper}_WORKER_VERSION) + {{ + alworker_send_systemparam(wtask, wcomp->channels(), + wcomp->samplingrate(), + wcomp->samplebitwidth()); + alworker_send_start(wtask); + }} + else + {{ + wcomp->publish_event(AL_EVENT_WRONGVERSION, version); + }} +}}''' + +COMP_CXX_ERRO = ''' + +void alusr_{workername}::{workername}_msglistener::error( + audiolite_workercomp *wcomp, al_wtask_t *wtask, int id, int ercode) +{{ +}}''' + +COMP_CXX_DEBG = ''' + +void alusr_{workername}::{workername}_msglistener::debug( + audiolite_workercomp *wcomp, al_wtask_t *wtask, int code) +{{ +}}''' + +COMP_CXX_INFO = ''' + +void alusr_{workername}::{workername}_msglistener::info( + audiolite_workercomp *wcomp, al_wtask_t *wtask, + int id, int chs, int fs, int layer, int rate) +{{ +}}''' + +COMP_CXX_DONE = ''' + +void alusr_{workername}::{workername}_msglistener::done( + audiolite_workercomp *wcomp, al_wtask_t *wtask, int id) +{{ +}}''' + +COMP_CXX_TERM = ''' + +void alusr_{workername}::{workername}_msglistener::term( + audiolite_workercomp *wcomp) +{{ +}}''' + +COMP_CXX_IMEM = ''' + +audiolite_memapbuf *alusr_{workername}::{workername}_msglistener::release_inmem( + audiolite_workercomp *wcomp, al_wtask_t *wtask, + audiolite_memapbuf *mem, int size) +{{ + return NULL; +}}''' + +COMP_CXX_OMEM = ''' + +audiolite_memapbuf *alusr_{workername}::{workername}_msglistener::release_outmem( + audiolite_workercomp *wcomp, al_wtask_t *wtask, + audiolite_memapbuf *mem) +{{ + push_data(wcomp, mem); + return NULL; +}}''' + +COMP_CXX_USER = ''' + +void alusr_{workername}::{workername}_msglistener::usermsg( + audiolite_workercomp *wcomp, al_wtask_t *wtask, + al_comm_msghdr_t hdr, al_comm_msgopt_t *opt) +{{ +}}''' + +COMPONENT_MK_BEFORE_APP = '''CXXSRCS += alusr_{workername}.cxx + +''' + +COMPONENT_MK_AFTER_APP = ''' +build_{workername}_worker: +\t@$(MAKE) -C {workername} TOPDIR="$(TOPDIR)" SDKDIR="$(SDKDIR)" APPDIR="$(APPDIR)" CROSSDEV=$(CROSSDEV) + +clean_{workername}_worker: +\t@$(MAKE) -C {workername} TOPDIR="$(TOPDIR)" SDKDIR="$(SDKDIR)" APPDIR="$(APPDIR)" CROSSDEV=$(CROSSDEV) clean + +$(OBJS): build_{workername}_worker + +clean:: clean_{workername}_worker +''' + +############################################################################ +### Template Audiolite component for this worker (cxx source) + +def create_worker_makefile(wkdir, wkname): + worker_make = wkdir + '/Makefile' + with open(worker_make, "w") as f: + f.write(MAKEFILE_TEMPLATE.format(workername=wkname)) + print(' [G] Generate ' + worker_make) + return True + +def code_commentout(en, code): + return '/* ' + code + ' */' if en else code + +def code_gen(en, code): + return code if en else '' + +def create_component(tgtdir, wkname, imemq, omemq, opts): + nameupper = wkname.upper() + init_outmempool = INIT_OUTMEMPOOL if omemq != 0 else '' + + comp_hfname = tgtdir + '/' + 'alusr_' + wkname + '.h' + comp_cxfname = tgtdir + '/' + 'alusr_' + wkname + '.cxx' + makefile_name = tgtdir + '/Makefile' + keep_makefile_name = tgtdir + '/Makefile_org' + + with open(comp_hfname, "w") as f: + f.write(COMPONENT_HEADER_TEMPLATE.format( + nameupper = nameupper, + workername = wkname, + cp_erro = code_gen(opts[COMP_OPT_ERRO], CP_ERROM), + cp_info = code_gen(opts[COMP_OPT_INFO], CP_INFOM), + cp_done = code_gen(opts[COMP_OPT_DONE], CP_DONEM), + cp_term = code_gen(opts[COMP_OPT_TERM], CP_TERMM), + cp_imem = code_gen(opts[COMP_OPT_IMEM] and imemq != 0, CP_IMEMM), + cp_omem = code_gen(opts[COMP_OPT_OMEM] and omemq != 0, CP_OMEMM), + cp_user = code_gen(opts[COMP_OPT_USER], CP_USERM), + cp_debg = code_gen(opts[COMP_OPT_DEBG], CP_DEBGM))) + + print(' [G] Generate ' + comp_hfname) + + with open(comp_cxfname, "w") as f: + cxx_template = COMPONENT_CXX_TEMPLATE + \ + code_gen(opts[COMP_OPT_ERRO], COMP_CXX_ERRO) + \ + code_gen(opts[COMP_OPT_INFO], COMP_CXX_INFO) + \ + code_gen(opts[COMP_OPT_DONE], COMP_CXX_DONE) + \ + code_gen(opts[COMP_OPT_TERM], COMP_CXX_TERM) + \ + code_gen(opts[COMP_OPT_IMEM] and imemq != 0, COMP_CXX_IMEM) + \ + code_gen(opts[COMP_OPT_OMEM] and omemq != 0, COMP_CXX_OMEM) + \ + code_gen(opts[COMP_OPT_USER], COMP_CXX_USER) + \ + code_gen(opts[COMP_OPT_DEBG], COMP_CXX_DEBG) + + f.write(cxx_template.format(nameupper = nameupper, + workername = wkname, + init_outmempool = init_outmempool, + imem = imemq, omem = omemq)) + print(' [G] Generate ' + comp_cxfname) + + if not os.path.exists(makefile_name): + print('Skip : No ' + makefile_name) + print(' Skip modification of the Makefile') + return + + print(' [C] Save ' + makefile_name + ' to ' + keep_makefile_name) + shutil.move(makefile_name, keep_makefile_name) + with open(keep_makefile_name, "r") as rf: + with open(makefile_name, "w") as wf: + lines = rf.readlines() + add_content = True + + for l in lines: + if add_content: + if 'include' in l and 'Application.mk' in l: + wf.write(COMPONENT_MK_BEFORE_APP.format(workername = wkname)) + wf.write(l) + wf.write(COMPONENT_MK_AFTER_APP.format(workername = wkname)) + add_content = False + print(' [M] Modify ' + makefile_name) + else: + wf.write(l) + else: + wf.write(l) + +def create_worker_source(wkdir, wkname, imemq, omemq, wkopt): + nouse_paus = code_commentout(wkopt[WORKER_OPT_PAUS], CONFIG_DEF_PAUS) + nouse_debg = code_commentout(wkopt[WORKER_OPT_DEBG], CONFIG_DEF_DEBG) + nouse_gain = code_commentout(wkopt[WORKER_OPT_GAIN], CONFIG_DEF_GAIN) + nouse_user = code_commentout(wkopt[WORKER_OPT_USER], CONFIG_DEF_USER) + nouse_strt = code_commentout(wkopt[WORKER_OPT_STRT], CONFIG_DEF_STRT) + nouse_stop = code_commentout(wkopt[WORKER_OPT_STOP], CONFIG_DEF_STOP) + + nameupper = wkname.upper() + + config_fname = wkdir + '/' + 'alworker_commfw_config.h' + worker_hfname = wkdir + '/' + wkname + '_worker_main.h' + worker_mfname = wkdir + '/' + wkname + '_worker_main.c' + ignore_fname = wkdir + '/' + '.gitignore' + + # Create .gitignore file + with open(ignore_fname, "w") as f: + f.write(WORKER_GITIGNORE_TEMPLATE.format(workername = wkname)) + print(' [G] Generate ' + ignore_fname) + + # Create config file + with open(config_fname, "w") as f: + f.write(WORKER_CONFIG_TEMPLATE.format(nouse_paus = nouse_paus, + nouse_debg = nouse_debg, + nouse_gain = nouse_gain, + nouse_user = nouse_user, + nouse_strt = nouse_strt, + nouse_stop = nouse_stop, + imem = imemq, omem = omemq)) + print(' [G] Generate ' + config_fname) + + # Create skelton source header + with open(worker_hfname, "w") as f: + f.write(WORKER_MAIN_HEADER.format(nameupper = nameupper)) + print(' [G] Generate ' + worker_hfname) + + # Create skelton source file + with open(worker_mfname, "w") as f: + f.write(WORKER_MAIN_SRC.format(workername = wkname, + nameupper = nameupper, + on_play = code_gen(wkopt[WORKER_OPT_DEFT], ON_PLAYF), + on_stpm = code_gen(wkopt[WORKER_OPT_DEFT], ON_STPMF), + on_term = code_gen(wkopt[WORKER_OPT_DEFT], ON_TERMF), + on_info = code_gen(wkopt[WORKER_OPT_INFO], ON_INFOF), + on_strt = code_gen(wkopt[WORKER_OPT_STRT], ON_STARTF), + on_stop = code_gen(wkopt[WORKER_OPT_STOP], ON_STOPF), + on_gain = code_gen(wkopt[WORKER_OPT_GAIN], ON_GAINF), + on_paus = code_gen(wkopt[WORKER_OPT_PAUS], ON_PAUSF), + on_user = code_gen(wkopt[WORKER_OPT_USER], ON_USERF), + on_omem = code_gen(wkopt[WORKER_OPT_OMEM], ON_OMEMF), + on_imem = code_gen(wkopt[WORKER_OPT_IMEM], ON_IMEMF), + on_debg = code_gen(wkopt[WORKER_OPT_DEBG], ON_DEBGF), + set_play = code_gen(wkopt[WORKER_OPT_DEFT], SET_PLAYMSG), + set_stop = code_gen(wkopt[WORKER_OPT_DEFT], SET_STOPMSG), + set_term = code_gen(wkopt[WORKER_OPT_DEFT], SET_TERMMSG), + set_info = code_gen(wkopt[WORKER_OPT_INFO], SET_PARAM), + set_strt = code_gen(wkopt[WORKER_OPT_STRT], SET_STARTING), + set_sping = code_gen(wkopt[WORKER_OPT_STOP], SET_STOPPING), + set_gain = code_gen(wkopt[WORKER_OPT_GAIN], SET_GAIN), + set_paus = code_gen(wkopt[WORKER_OPT_PAUS], SET_PAUSE), + set_user = code_gen(wkopt[WORKER_OPT_USER], SET_USRMSG), + set_imem = code_gen(wkopt[WORKER_OPT_IMEM], SET_IMEM), + set_omem = code_gen(wkopt[WORKER_OPT_OMEM], SET_OMEM), + set_debg = code_gen(wkopt[WORKER_OPT_DEBG], SET_DBGMSG))) + print(' [G] Generate ' + worker_mfname) + +def generate_workercomp(wkname, basedir, imemq, omemq, wk_opt, cp_opt): + wkdir = basedir + '/' + wkname + comp_hname = basedir + '/alusr_' + wkname + '.h' + comp_cxname = basedir + '/alusr_' + wkname + '.cxx' + + if not os.path.exists(basedir): + print('Error : No exists : ' + basedir + ' directory.', file=sys.stderr) + return False + + if os.path.exists(wkdir): + print('Error : ' + wkdir + ' already exists.', file=sys.stderr) + return False + + if os.path.exists(comp_hname) or os.path.exists(comp_cxname): + print('Error : ' + comp_cxname + ' class already exists.', file=sys.stderr) + return False + + try: + os.mkdir(wkdir) + except: + print('Error : Could not make direcotry : ' + wkdir, file=sys.stderr) + return False + + create_worker_makefile(wkdir, wkname) + create_worker_source(wkdir, wkname, imemq, omemq, wk_opt) + create_component(basedir, wkname, imemq, omemq, cp_opt) + + return True + +class char_check(object): + def __init__(self, strs): + self.strs = strs + slist = list(strs) + self.opt = dict(zip(slist, [False] * len(slist))) + + def __contains__(self, val): + strs = list(val) + for s in strs: + if s in self.opt: + self.opt[s] = True + else: + return False + return True + + def __iter__(self): + return iter((self.strs)) + +if __name__ == '__main__': + import argparse + + worker_optchk = char_check(WORKER_OPTS) + comp_optchk = char_check(COMP_OPTS) + + parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, + description = TOOL_DESCRIPTION, + epilog = EPILOG) + + parser.add_argument('workername', metavar='', + type = str, help = 'New woreker name\n') + parser.add_argument('-d', '--dir', type=str, default = '.', + help = 'Execution directory (default is current directory)\n') + parser.add_argument('-w', '--worker', type=str, choices = worker_optchk, + help = worker_opt_help) + parser.add_argument('-c', '--component', type=str, choices = comp_optchk, + help = comp_opt_help) + parser.add_argument('-i', '--imem', type=int, choices = range(9), + default = 8, help='Input queue depth (default 8)\n') + parser.add_argument('-o', '--omem', type=int, choices = range(9), + default = 8, help='Input queue depth (default 8)\n') + opts = parser.parse_args() + + print('=== Generating audiolite worker component in ' + opts.dir) + if generate_workercomp(opts.workername, opts.dir, opts.imem, opts.omem, + worker_optchk.opt, comp_optchk.opt): + print('Done in successfly') + else: + print('Error...') + diff --git a/sdk/tools/build-env.sh b/sdk/tools/build-env.sh index 8b5564a85..73c1d6eec 100755 --- a/sdk/tools/build-env.sh +++ b/sdk/tools/build-env.sh @@ -265,3 +265,9 @@ else echo " The spresense tools completion can not work well" echo " because of old bash version." fi + +# +# Tool path setup +# + +export PATH=${SCRIPT_DIR}/bin:$PATH diff --git a/sdk/tools/flash_writer/scripts/xmodem.py b/sdk/tools/flash_writer/scripts/xmodem.py index 0557366b6..cdfcc5eef 100644 --- a/sdk/tools/flash_writer/scripts/xmodem.py +++ b/sdk/tools/flash_writer/scripts/xmodem.py @@ -117,7 +117,10 @@ import time import sys from functools import partial -import collections +try: + from collections.abc import Callable +except ImportError: + from collections import Callable # Loggerr log = logging.getLogger('xmodem') @@ -310,12 +313,12 @@ def callback(total_packets, success_count, error_count) char = self.getc(1, timeout) if char == ACK: success_count += 1 - if isinstance(callback, collections.Callable): + if isinstance(callback, Callable): callback(total_packets, success_count, error_count) break if char == NAK: error_count += 1 - if isinstance(callback, collections.Callable): + if isinstance(callback, Callable): callback(total_packets, success_count, error_count) if error_count >= retry: # excessive amounts of retransmissions requested, @@ -329,7 +332,7 @@ def callback(total_packets, success_count, error_count) else: log.error('Not ACK, Not NAK') error_count += 1 - if isinstance(callback, collections.Callable): + if isinstance(callback, Callable): callback(total_packets, success_count, error_count) if error_count >= retry: # excessive amounts of retransmissions requested, diff --git a/sdk/tools/mkcmd.py b/sdk/tools/mkcmd.py index 80211f0a4..99f6f9048 100755 --- a/sdk/tools/mkcmd.py +++ b/sdk/tools/mkcmd.py @@ -87,7 +87,7 @@ ASRCS = CSRCS = -MAINSRC = {appname}_main.c +MAINSRC = {appname}_main.{ext} include $(APPDIR)/Application.mk ''' @@ -102,7 +102,7 @@ #include #include -int main(int argc, FAR char *argv[]) +{extern_desc}int main(int argc, FAR char *argv[]) {{ return 0; }} @@ -119,12 +119,13 @@ /*.adb /*.lib /*.src +/*.spk ''' -def create_from_template(template, filename, appname, configname, menudesc=None): +def create_from_template(template, filename, appname, configname, ext, extern_desc, menudesc=None): with open(filename, "w") as f: - f.write(template.format(appname=appname, configname=configname, - menudesc=menudesc)) + f.write(template.format(appname=appname, configname=configname, ext=ext, + extern_desc=extern_desc, menudesc=menudesc)) if __name__ == '__main__': @@ -137,6 +138,7 @@ def create_from_template(template, filename, appname, configname, menudesc=None) parser.add_argument('desc', type=str, nargs="?", help='Menu description') parser.add_argument('-d', '--basedir', type=str, default='examples', help='Base directory to create new application') + parser.add_argument('-x', '--cplusplus', action='store_true', help='Generate C++ code') parser.add_argument('-v', '--verbose', action='count', default=0, help='Verbose messages') opts = parser.parse_args() @@ -145,7 +147,9 @@ def create_from_template(template, filename, appname, configname, menudesc=None) appname = opts.appname optprefix = os.path.basename(os.path.normpath(opts.basedir)).upper() configname = optprefix + '_' + appname.upper() - maincsrcfile = appname + '_main.c' + ext = 'cxx' if opts.cplusplus else 'c' + extern_desc = 'extern "C" ' if opts.cplusplus else '' + mainsrcfile = appname + '_main.' + ext sdkdir = os.path.abspath(os.path.join(sys.argv[0], '..', '..')) # @@ -185,10 +189,10 @@ def create_from_template(template, filename, appname, configname, menudesc=None) os.chdir(targetdir) - create_from_template(KCONFIG_TMPL, 'Kconfig', appname, configname, menudesc) - create_from_template(MAKEFILE_TMPL, 'Makefile', appname, configname) - create_from_template(MAKEDEFS_TMPL, 'Make.defs', appname, configname) - create_from_template(MAINCSRC_TMPL, maincsrcfile, appname, configname) + create_from_template(KCONFIG_TMPL, 'Kconfig', appname, configname, ext, extern_desc, menudesc) + create_from_template(MAKEFILE_TMPL, 'Makefile', appname, configname, ext, extern_desc) + create_from_template(MAKEDEFS_TMPL, 'Make.defs', appname, configname, ext, extern_desc) + create_from_template(MAINCSRC_TMPL, mainsrcfile, appname, configname, ext, extern_desc) with open('.gitignore', "w") as f: f.write(GITIGNORE) diff --git a/sdk/tools/mkexport.sh b/sdk/tools/mkexport.sh deleted file mode 100755 index fb7b170d1..000000000 --- a/sdk/tools/mkexport.sh +++ /dev/null @@ -1,414 +0,0 @@ -#!/usr/bin/env bash -# tools/mkexport.sh -# -# Copyright (C) 2011-2012, 2014, 2016 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt -# -# Copyright 2018 Sony Semiconductor Solutions Corporation -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# - -# Get the input parameter list - -USAGE="USAGE: $0 [-d] [-z] -t -s [-x ] -l \"lib1 [lib2 [lib3 ...]]\"" -unset TOPDIR -unset LIBLIST -unset TGZ -USRONLY=n -LIBEXT=.a - -while [ ! -z "$1" ]; do - case $1 in - -d ) - set -x - ;; - -l ) - shift - LIBLIST=$1 - ;; - -t ) - shift - TOPDIR=$1 - ;; - -s ) - shift - SDKDIR=$1 - ;; - -u ) - USRONLY=y - ;; - -w | -wn | -wy) - # TODO: ignore now - ;; - -x ) - shift - LIBEXT=$1 - ;; - -z ) - TGZ=y - ;; - -h ) - echo $USAGE - exit 0 - ;; - * ) - echo "Unrecognized argument: $1" - echo $USAGE - exit 1 - ;; - esac - shift -done - -# Check arguments - -if [ -z "${TOPDIR}" -o -z "${LIBLIST}" ]; then - echo "MK: Missing required arguments" - echo $USAGE - exit 1 -fi - -if [ ! -d "${TOPDIR}" ]; then - echo "MK: Directory ${TOPDIR} does not exist" - exit 1 -fi - -# Check configuration -# Verify that we have Make.defs, .config, and .version files. - -if [ ! -f "${TOPDIR}/Make.defs" ]; then - echo "MK: Directory ${TOPDIR}/Make.defs does not exist" - exit 1 -fi - -if [ ! -f "${TOPDIR}/include/nuttx/config.h" ]; then - echo "MK: File ${TOPDIR}/include/nuttx/config.h does not exist" - exit 1 -fi - -if [ ! -f "${TOPDIR}/.version" ]; then - echo "MK: File ${TOPDIR}/.version does not exist" - exit 1 -fi - -if [ ! -f "${SDKDIR}/.config" ]; then - echo "MK: File ${SDKDIR}/.config does not exist" - exit 1 -fi - -# Check if the make environment variable has been defined - -if [ -z "${MAKE}" ]; then - MAKE=`which make` -fi - -# Get the version string - -#source "${SDKDIR}/.version" -#if [ ! -z "${CONFIG_VERSION_STRING}" -a "${CONFIG_VERSION_STRING}" != "0.0" ]; then -# VERSION="-${CONFIG_VERSION_STRING}" -#fi -if [ -f "${SDKDIR}"/sdk_version ]; then - VERSION="-`cat ${SDKDIR}/sdk_version`" -fi - -# Check whether the environment is Cygwin and create the export directory - -if [ $(uname -o 2>/dev/null) = "Cygwin" ]; then - TMPDIR=`mktemp -d | cygpath -m -f -` -else - TMPDIR=`mktemp -d` -fi -OUTPUTDIR="sdk-export${VERSION}" -EXPORTDIR="${TMPDIR}/${OUTPUTDIR}" -EXPORTNXDIR="${EXPORTDIR}/nuttx" -EXPORTSDKDIR="${EXPORTDIR}/sdk" - -# If the export directory already exists, then remove it and create a new one - -if [ -d "${EXPORTDIR}" ]; then - echo "MK: Removing old export directory" - rm -rf "${EXPORTDIR}" -fi - -# Remove any possible previous results - -rm -f "${OUTPUTDIR}.tar" -rm -f "${OUTPUTDIR}.zip" -rm -f "${OUTPUTDIR}.tar.gz" - -# Create the export directory and some of its subdirectories - -mkdir "${EXPORTDIR}" || { echo "MK: 'mkdir ${EXPORTDIR}' failed"; exit 1; } -mkdir "${EXPORTNXDIR}" || { echo "MK: 'mkdir ${EXPORTNXDIR}' failed"; exit 1; } -mkdir "${EXPORTNXDIR}/startup" || { echo "MK: 'mkdir ${EXPORTNXDIR}/startup' failed"; exit 1; } -mkdir "${EXPORTNXDIR}/build" || { echo "MK: 'mkdir ${EXPORTNXDIR}/build' failed"; exit 1; } -mkdir "${EXPORTNXDIR}/arch" || { echo "MK: 'mkdir ${EXPORTNXDIR}/arch' failed"; exit 1; } -mkdir "${EXPORTNXDIR}/tools" || { echo "MK: 'mkdir ${EXPORTNXDIR}/tools' failed"; exit 1; } -mkdir "${EXPORTSDKDIR}" || { echo "MK: 'mkdir ${EXPORTSDKDIR}' failed"; exit 1; } -mkdir -p "${EXPORTSDKDIR}/bsp/include/sdk" || { echo "MK: 'mkdir ${EXPORTSDKDIR}/bsp/include/sdk' failed"; exit 1; } -mkdir -p "${EXPORTSDKDIR}/bsp/include/sdk/chip" || { echo "MK: 'mkdir ${EXPORTSDKDIR}/bsp/include/sdk/chip' failed"; exit 1; } -mkdir -p "${EXPORTSDKDIR}/modules/include" || { echo "MK: 'mkdir ${EXPORTSDKDIR}/modules/include' failed"; exit 1; } -mkdir "${EXPORTSDKDIR}/libs" || { echo "MK: 'mkdir ${EXPORTSDKDIR}/libs' failed"; exit 1; } -mkdir "${EXPORTSDKDIR}/tools" || { echo "MK: 'mkdir ${EXPORTSDKDIR}/tools' failed"; exit 1; } -mkdir -p "${EXPORTSDKDIR}/bsp/scripts" || { echo "MK: 'mkdir ${EXPORTSDKDIR}/bsp/scripts' failed"; exit 1; } -mkdir -p "${EXPORTSDKDIR}/system/builtin/registry" || { echo "MK: 'mkdir ${EXPORTSDKDIR}/system/builtin/registry' failed"; exit 1; } - -# Copy the .config file - -cp -a "${TOPDIR}/.config" "${EXPORTNXDIR}/.config" || - { echo "MK: Failed to copy ${TOPDIR}/.config to ${EXPORTNXDIR}/.config"; exit 1; } -cp -a "${SDKDIR}/.config" "${EXPORTSDKDIR}/.config" || - { echo "MK: Failed to copy ${SDKDIR}/.config to ${EXPORSDKTDIR}/.config"; exit 1; } - -# Copy the Make.defs files, but disable windows path conversions - -grep -v "WINTOOL[ \t]*=[ \t]y" "${TOPDIR}/Make.defs" > "${EXPORTNXDIR}/Make.defs" - -# Extract information from the Make.defs file. A Makefile can do this best - -${MAKE} -C "${TOPDIR}/tools" -f Makefile.export TOPDIR="${TOPDIR}" EXPORTDIR="${EXPORTNXDIR}" -source "${EXPORTNXDIR}/makeinfo.sh" -rm -f "${EXPORTNXDIR}/makeinfo.sh" -rm -f "${EXPORTNXDIR}/Make.defs" - -# Verify the build info that we got from makeinfo.sh - -if [ ! -d "${ARCHDIR}" ]; then - echo "MK: Directory ${ARCHDIR} does not exist" - exit 1 -fi - -# Is there a linker script in this configuration? - -if [ ! -z "${LDPATH}" ]; then - - # Apparently so. Verify that the script exists - - if [ ! -f "${LDPATH}" ]; then - echo "MK: File ${LDPATH} does not exist" - exit 1 - fi - - # Copy the linker script - - cp -p "${LDPATH}" "${EXPORTNXDIR}/build/." || \ - { echo "MK: cp ${LDPATH} failed"; exit 1; } -fi - -# Copy the NuttX include directory (retaining attributes and following symbolic links) - -cp -LR -p "${TOPDIR}/include" "${EXPORTNXDIR}/." || \ - { echo "MK: 'cp ${TOPDIR}/include' failed"; exit 1; } - -# Copy architecture-specific header files into the arch export sub-directory. -# This is tricky because each architecture does things in a little different -# way. -# -# First copy any header files in the architecture src/ sub-directory (some -# architectures keep all of the header files there, some a few, and others -# none - -cp -LR -f "${ARCHDIR}"/*.h "${EXPORTNXDIR}"/arch/. 2>/dev/null - -# Copy SDK header files -cp -LR -pf "${SDKDIR}"/bsp/include/arch "${EXPORTNXDIR}"/include/. -cp -rp "${SDKDIR}"/bsp/include/sdk/*.h "${EXPORTSDKDIR}"/bsp/include/sdk/. -cp -rp "${SDKDIR}"/modules/include/* "${EXPORTSDKDIR}"/modules/include/. - -# An unnecessary copy, but copying driver headers so using in Arduino library. -cp -rp "${SDKDIR}"/bsp/src/*.h "${EXPORTSDKDIR}"/bsp/include/sdk/. -cp -rp "${SDKDIR}"/bsp/src/chip/*.h "${EXPORTSDKDIR}"/bsp/include/sdk/chip/. - -# Import build related tools and files - -cp -f "${TOPDIR}"/tools/Config.mk "${EXPORTNXDIR}"/tools/. -cp -f "${TOPDIR}"/tools/Makefile.host "${EXPORTNXDIR}"/tools/. -cp -f "${TOPDIR}"/tools/mkdeps.c "${EXPORTNXDIR}"/tools/. -cp -f "${TOPDIR}"/tools/incdir.sh "${EXPORTNXDIR}"/tools/. -cp -f "${TOPDIR}"/tools/incdir.bat "${EXPORTNXDIR}"/tools/. -cp "${ARCHDIR}"/armv7-m/Toolchain.defs "${EXPORTNXDIR}"/build/. -cat "${TOPDIR}"/Make.defs | sed -e 's,.*/Toolchain.defs,include ${TOPDIR}/build/Toolchain.defs,' >"${EXPORTNXDIR}"/Make.defs - -cp -f "${SDKDIR}"/Make.defs "${EXPORTSDKDIR}"/. -cp -f "${SDKDIR}"/bsp/scripts/Make.defs.userapps "${EXPORTSDKDIR}"/Make.defs -cp -frp "${SDKDIR}"/tools/* "${EXPORTSDKDIR}"/tools/ - -# Copy builtin command source -# -# This process needs to be able to user adds his application to nsh builtin command. - -cp -f "${SDKDIR}"/system/builtin/Make.defs "${EXPORTSDKDIR}"/system/builtin/. -cp -f "${SDKDIR}"/system/builtin/Makefile "${EXPORTSDKDIR}"/system/builtin/Makefile -cp -f "${SDKDIR}"/system/builtin/*.c "${EXPORTSDKDIR}"/system/builtin/. -cp -f "${SDKDIR}"/system/builtin/*.h "${EXPORTSDKDIR}"/system/builtin/. -cp -f "${SDKDIR}"/system/builtin/registry/*dat "${EXPORTSDKDIR}"/system/builtin/registry/. 2>/dev/null -cp -f "${SDKDIR}"/system/builtin/registry/Makefile.external "${EXPORTSDKDIR}"/system/builtin/registry/Makefile - -# Then look a list of possible places where other architecture-specific -# header files might be found. If those places exist (as directories or -# as symbolic links to directories, then copy the header files from -# those directories into the EXPORTDIR - -ARCH_HDRDIRS="arm armv7-m avr avr32 board common chip mips32" -for hdir in $ARCH_HDRDIRS; do - - # Does the directory (or symbolic link) exist? - - if [ -d "${ARCHDIR}/${hdir}" -o -h "${ARCHDIR}/${hdir}" ]; then - - # Yes.. create a export sub-directory of the same name - - mkdir "${EXPORTNXDIR}/arch/${hdir}" || \ - { echo "MK: 'mkdir ${EXPORTNXDIR}/arch/${hdir}' failed"; exit 1; } - - # Then copy the header files (only) into the new directory - - cp -f "${ARCHDIR}"/${hdir}/*.h "${EXPORTNXDIR}"/arch/${hdir}/. 2>/dev/null - - # One architecture has low directory called "chip" that holds the - # header files - - if [ -d "${ARCHDIR}/${hdir}/chip" ]; then - - # Yes.. create a export sub-directory of the same name - - mkdir "${EXPORTNXDIR}/arch/${hdir}/chip" || \ - { echo "MK: 'mkdir ${EXPORTNXDIR}/arch/${hdir}/chip' failed"; exit 1; } - - # Then copy the header files (only) into the new directory - - cp -f "${ARCHDIR}"/${hdir}/chip/*.h "${EXPORTNXDIR}"/arch/${hdir}/chip/. 2>/dev/null - fi - fi -done - -# Copy OS internal header files as well. They are used by some architecture- -# specific header files. - -mkdir "${EXPORTNXDIR}/arch/os" || \ - { echo "MK: 'mkdir ${EXPORTNXDIR}/arch/os' failed"; exit 1; } - -OSDIRS="clock environ errno group init irq mqueue paging pthread sched semaphore signal task timer wdog" - -for dir in ${OSDIRS}; do - mkdir "${EXPORTNXDIR}/arch/os/${dir}" || \ - { echo "MK: 'mkdir ${EXPORTNXDIR}/arch/os/${dir}' failed"; exit 1; } - cp -f "${TOPDIR}"/sched/${dir}/*.h "${EXPORTNXDIR}"/arch/os/${dir}/. 2>/dev/null -done - -# Copy External CMSIS header files - -mkdir "${EXPORTNXDIR}/include/cmsis" || { echo "MK: 'mkdir ${EXPORTNXDIR}/include/cmsis' failed"; exit 1; } -cp -rp "${SDKDIR}"/../externals/cmsis/CMSIS_5/CMSIS/NN/Include/* "${EXPORTNXDIR}/include/cmsis" -cp -rp "${SDKDIR}"/../externals/cmsis/CMSIS_5/CMSIS/DSP/Include/* "${EXPORTNXDIR}/include/cmsis" -cp -rp "${SDKDIR}"/../externals/cmsis/CMSIS_5/CMSIS/Core/Include/* "${EXPORTNXDIR}/include/cmsis" - -# Copy External mbedTLS header files - -mkdir "${EXPORTNXDIR}/include/mbedtls" || { echo "MK: 'mkdir ${EXPORTNXDIR}/include/mbedtls' failed"; exit 1; } -cp -rp "${SDKDIR}"/../externals/alt_stubs/mbedtls/include/mbedtls/* "${EXPORTNXDIR}/include/mbedtls" - -# Add the board library to the list of libraries - -LIBLIST="${LIBLIST} bsp/board/libboard${LIBEXT}" - -# Then process each library - -ARTMPDIR=`mktemp -d` -AR=${CROSSDEV}ar -STRIP=${CROSSDEV}strip -for lib in ${LIBLIST}; do - if [ ! -f "${SDKDIR}/${lib}" ]; then - echo "MK: Library ${SDKDIR}/${lib} does not exist" - exit 1 - fi - - # Get some shorter names for the library - - libname=`basename ${lib} ${LIBEXT}` - shortname=`echo ${libname} | sed -e "s/^lib//g"` - - # Copy the application library unmodified - - if [ "X${libname}" = "Xlibapps" ]; then - cp -p "${SDKDIR}/${lib}" "${EXPORTSDKDIR}/libs/." || \ - { echo "MK: cp ${TOPDIR}/${lib} failed"; exit 1; } - else - echo "Merging archive: `basename ${lib} ${LIBEXT}`" - # Save current working directory - - PREVDIR="$PWD" - - # Create a temporary directory and extract all of the objects there - # Hmmm.. this probably won't work if the archiver is not 'ar' - - cd "${ARTMPDIR}" - ${AR} x "${SDKDIR}/${lib}" - - # Rename each object file (to avoid collision when they are combined) - # and add the file to libnuttx - - for file in `${AR} t ${SDKDIR}/${lib} | sed -e "s/[\r\n]\+//g"`; do - mv "${file}" "${shortname}-${file}" - ${AR} rcs "${EXPORTSDKDIR}/libs/libsdk${LIBEXT}" "${shortname}-${file}" - done - - # Remove debugging symbols - - ${STRIP} -g "${EXPORTSDKDIR}/libs/libsdk${LIBEXT}" - - # Remove all of extracted object files - - rm -f *.o - - cd "${PREVDIR}" - fi -done - -# Copy LICENSE file -cp -f "${SDKDIR}"/../LICENSE "${EXPORTDIR}"/LICENSE - -# Now tar up the whole export directory - -cd "${TMPDIR}" || \ - { echo "MK: 'cd ${TMPDIR}' failed"; exit 1; } - -if [ "X${TGZ}" = "Xy" ]; then - tar cvf "${OUTPUTDIR}.tar" "${OUTPUTDIR}" 1>/dev/null 2>&1 - gzip -f "${OUTPUTDIR}.tar" - cp "${OUTPUTDIR}.tar.gz" "${SDKDIR}" -else - zip -r "${OUTPUTDIR}.zip" "${OUTPUTDIR}" 1>/dev/null 2>&1 - cp "${OUTPUTDIR}.zip" "${SDKDIR}" -fi - -# Clean up after ourselves - -rm -rf "${TMPDIR}" diff --git a/sdk/tools/mkversion.sh b/sdk/tools/mkversion.sh index 758767d35..c7ad56433 100755 --- a/sdk/tools/mkversion.sh +++ b/sdk/tools/mkversion.sh @@ -36,7 +36,7 @@ TAG=${1:-HEAD} -SDK_VERSION="SDK3.2.0" +SDK_VERSION="SDK3.3.0" if [ -r sdk_version ]; then SDK_VERSION="SDK`cat sdk_version`" fi