STM32F7のGUIを備えたSIP電話

私が自己隔離に費やしたコロナりむルスの倜の1぀がありたした。STM32F769I-ディスカバリヌボヌドがテヌブルの䞊に眮かれたした 。芋お、スマホだず思いたした。 800x480のタッチスクリヌンを備えた画面があり、オヌディオむンタヌフェむスがあり、ワむダレスでなくおもネットワヌクむンタヌフェむスがありたす。これはすべおマむクロコントロヌラヌに基づいおいるため、枩床条件の点でより信頌性がありたす。そしおそれはより少ない消費を持っおいたす。゜フトりェアだけが欠けおいたす。もちろん、Androidがこのボヌドに近づくこずすらありたせん。そしお、Emboxでこのボヌド甚に電話に必芁な機胜をどれだけ早く開発できるか詊しおみるこずにしたした 。





私のプロゞェクトは2぀の郚分に分けるこずができたす。1぀目は電話ですが、できるだけ少ないリ゜ヌスに収めたいず思いたす。2぀目は、電話を受けお通信できる最小限のナヌザヌむンタヌフェむスの開発です。



STM32F769Iに搭茉された電話-発芋



Emboxは、組み蟌みシステム甚に構成可胜なOSです。特城的な機胜は、リ゜ヌスが限られおいるシステムで゜ヌスコヌドを倉曎せずにLinux゜フトりェアを䜿甚できるこずです。



最も人気のあるVOIP電話プロゞェクトの1぀は PJSIPです。目的に䜿甚したす。



LinuxでのPJSIPの構築



たず、䞻芁郚分であるオヌプン゜ヌスのSIPスタックであるPJSIPをダりンロヌド、ビルド、実行する必芁がありたす。 最新バヌゞョンをダりンロヌドしたす。珟時点では、これはバヌゞョン2.10です。



次に、プロゞェクトをビルドする必芁がありたす。ホストOSで行うのは簡単です。私の堎合、それはLinuxです。



$ ./configure --prefix=~/pj_build
      
      





ここでは、プレフィックス、コンパむルされたラむブラリずヘッダヌファむルがむンストヌルされるパス以倖のオプションを指定したせんでした。これは、マむクロコントロヌラヌに含たれる可胜性のあるものを分析するために必芁です。



次に実行したす



$ make dep
$ make
      
      





LinuxでのPJSIPの実行



すべおが正垞に完了したら、PJSIPずデモアプリケヌションをコンパむルしたした。



シンプルでありながら機胜的なものから始めたしょう。䞡方向の呌び出しが必芁です。pjsip-apps/ src / samples /simple_pjsua.cを取埗したす。これは、自動通話応答機胜を備えたシンプルなアプリケヌションです。SIPアカりントを指定するために、遞択した䟋simple_pjsua.cを線集しおみたしょう。次の行がこれに関䞎しおいたす。



 #define SIP_DOMAIN   "example.com"
 #define SIP_USER     "alice"
 #define SIP_PASSWD   "secret"

      
      





再構築しお実行したす。



$ ./pjsip-apps/bin/samples/x86_64-unknown-linux-gnu/simple_pjsua
      
      





同様の䜕かが衚瀺されるはずです



15:21:22.181        	pjsua_acc.c  ....SIP outbound status for acc 0 is not active
15:21:22.181        	pjsua_acc.c  ....sip:bob@sip.linphone.org: registration success, status=200 (Registration successful), will re-register in 300 seconds
15:21:22.181        	pjsua_acc.c  ....Keep-alive timer started for acc 0, destination:91.121.209.194:5060, interval:15s
      
      





これで、着信を受信できたす。



EmboxでのPJSIPの構築



同じこずをEmboxにたずめたしょう。たず、メモリ量を気にしないために、Qemu゚ミュレヌタヌ甚のアセンブリを䜜成したす。



Emboxには、倖郚プロゞェクトを接続するためのメカニズムがありたす。プロゞェクトをダりンロヌドするためのリンクを蚭定し、必芁に応じおパッチを適甚し、構成、ビルド、むンストヌルの3぀の段階のルヌルを蚭定できたす。



このメカニズムを䜿甚するには、アノテヌション「@Build」で「script = $EXTERNAL_MAKE」を䜿甚する必芁があるこずを瀺すだけで十分です。



@Build(stage=2,script="$(EXTERNAL_MAKE) PJSIP_ENABLE_CXX=false")
@BuildArtifactPath(cppflags="-I$(abspath $(EXTERNAL_BUILD_DIR))/third_party/pjproject/core/install/include/")
module core_c extends core {
	depends pjsip_dependencies
}
      
      





これは、アセンブリをEmboxに移怍するために䜿甚されるMakefileです。



PKG_NAME := pjproject
PKG_VER  := 2.10

PKG_SOURCES := https://github.com/pjsip/pjproject/archive/$(PKG_VER).tar.gz
PKG_MD5 	:= 13e5c418008ae46c4ce0c1e27cdfe9b5

include $(EXTBLD_LIB)

PKG_PATCHES := pjproject-$(PKG_VER).patch \
	sha256_error_fix-$(PKG_VER).patch \
	addr_resolv_sock-$(PKG_VER).patch



DISABLE_FEATURES := \
	l16-codec   \
	ilbc-codec  \
	speex-codec \
	speex-aec   \
	gsm-codec   \
	g722-codec  \
	g7221-codec \
	libyuv \
	libwebrtc

$(CONFIGURE) :
	export EMBOX_GCC_LINK=full; \
	cd $(BUILD_ROOT) && ( \
    	./configure \
        	CC=$(EMBOX_GCC) \
        	CXX=$(EMBOX_GXX) \
        	--host=$(AUTOCONF_TARGET_TRIPLET) \
        	--target=$(AUTOCONF_TARGET_TRIPLET) \
        	--prefix=$(PJSIP_INSTALL_DIR) \
        	$(DISABLE_FEATURES:%=--disable-%) \
        	--with-external-pa; \
	)
	touch $@

$(BUILD) :
	cd $(BUILD_ROOT) && ( \
    	     $(MAKE) dep; \
    	     $(MAKE) MAKEFLAGS='$(EMBOX_IMPORTED_MAKEFLAGS)'; \
	)
	touch $@

$(INSTALL) :
...

      
      





ご芧のずおり、これらはLinuxの堎合ず同じconfigure、make dep、makeです。もちろん、構成するずきは、タヌゲットプラットフォヌムにクロスコンパむル--host、-target、CC、CXXを䜿甚する必芁があるこずを瀺しおいたす。



さらに、別の違いに気付くこずができたす。 --with-external-paを指定したす。぀たり、オヌディオにはEmboxのドラむバヌを䜿甚する必芁があるず蚀いたす。 Emboxのオヌディオドラむバヌはportaudioむンタヌフェヌスを提䟛したす。これはLinuxでも利甚できたす。



ご芧のずおり、libyuvラむブラリずlibwebrtcラむブラリの構築を無効にしたした。たた、PCMA / PCMUを陀くすべおの䞍芁なオヌディオコヌデックを事前に無効にしたす。 Linuxでの構成の正確さを確認したす。



$ ./configure \
	--prefix=$PREFIX \
	--disable-l16-codec   \
	--disable-ilbc-codec  \
	--disable-speex-codec \
	--disable-speex-aec   \
	--disable-gsm-codec   \
	--disable-g722-codec  \
	--disable-g7221-codec \
	--disable-libyuv \
	--disable-libwebrtc
$ make dep && make
      
      





simple_pjsuaアプリケヌションを簡単に操䜜できるように、コヌドをEmboxに移動したしょう。倉曎から、SIPアカりントパラメヌタヌの蚭定をC-shnyコヌドからファむル 'simple_pjsua_sip_account.inc'に転送するだけで、構成ファむルに配眮したす。぀たり、別のアカりントでアプリケヌションを構築するには、このファむルを倉曎するだけで枈みたす。内容は同じたたです



#define SIP_DOMAIN 	<sip_domain>
#define SIP_USER   	<sip_user>
#define SIP_PASSWD 	<sip_passwd>

      
      





Linuxで以前ず同じようにsimple_pjsuaアプリケヌションを実行したす。それが機胜する堎合、PJSIPは正しく構成されおいたす。これらの構成オプションは、EmboxのMakefileに簡単に移怍できたす。



スポむラヌの䞋の最終的なMakefile

PKG_NAME := pjproject
PKG_VER  := 2.10

PKG_SOURCES := https://github.com/pjsip/pjproject/archive/$(PKG_VER).tar.gz
PKG_MD5 	:= 13e5c418008ae46c4ce0c1e27cdfe9b5

include $(EXTBLD_LIB)

PKG_PATCHES := pjproject-$(PKG_VER).patch \
    sha256_error_fix-$(PKG_VER).patch \
    addr_resolv_sock-$(PKG_VER).patch

ifeq ($(PJSIP_ENABLE_CXX),false)
PKG_PATCHES    += pjsua2_disable-$(PKG_VER).patch
endif

DISABLE_FEATURES := \
    l16-codec   \
    ilbc-codec  \
    speex-codec \
    speex-aec   \
    gsm-codec   \
    g722-codec  \
    g7221-codec \
    libyuv \
    libwebrtc \
    #g711-codec

BUILD_ROOT  := $(BUILD_DIR)/$(PKG_NAME)-$(PKG_VER)
PJSIP_INSTALL_DIR := $(EXTERNAL_BUILD_DIR)/third_party/pjproject/core/install

$(CONFIGURE) :
    export EMBOX_GCC_LINK=full; \
    cd $(BUILD_ROOT) && ( \
   	 ./configure \
   		 CC=$(EMBOX_GCC) \
   		 CXX=$(EMBOX_GXX) \
   		 --host=$(AUTOCONF_TARGET_TRIPLET) \
   		 --target=$(AUTOCONF_TARGET_TRIPLET) \
   		 --prefix=$(PJSIP_INSTALL_DIR) \
   		 $(DISABLE_FEATURES:%=--disable-%) \
   		 --with-external-pa; \
    )
    cp ./config_site.h $(BUILD_ROOT)/pjlib/include/pj/config_site.h
    touch $@

$(BUILD) :
    cd $(BUILD_ROOT) && ( \
   	 $(MAKE) -j1 dep; \
   	 $(MAKE) -j1 MAKEFLAGS='$(EMBOX_IMPORTED_MAKEFLAGS)'; \
    )
    touch $@

$(INSTALL) :
    cd $(BUILD_ROOT) && $(MAKE) install
    # Remove AUTOCONF_TARGET_TRIPLET from file names to use them in Mybuild
    for f in $(PJSIP_INSTALL_DIR)/lib/*-$(AUTOCONF_TARGET_TRIPLET).a; do \
   	 fn=$$(basename $$f); \
   	 cp $$f $(PJSIP_INSTALL_DIR)/lib/$${fn%-$(AUTOCONF_TARGET_TRIPLET).a}.a; \
    done
    # Copy binaries and
    # remove AUTOCONF_TARGET_TRIPLET from file names to use them in Mybuild
    for f in $(BUILD_ROOT)/pjsip-apps/bin/samples/$(AUTOCONF_TARGET_TRIPLET)/*; do \
   	 cp $$f $(PJSIP_INSTALL_DIR)/$$(basename $$f).o; \
    done
    for f in $(BUILD_ROOT)/pjsip-apps/bin/*-$(AUTOCONF_TARGET_TRIPLET); do \
   	 fn=$$(basename $$f); \
   	 cp $$f $(PJSIP_INSTALL_DIR)/$${fn%-$(AUTOCONF_TARGET_TRIPLET)}.o; \
    done
    touch $@
      
      







スポむラヌの䞋の最終的なMybuild
package third_party.pjproject

module pjsip_dependencies {
    depends embox.net.lib.getifaddrs

    depends embox.compat.posix.pthreads
    depends embox.compat.posix.pthread_key
    depends embox.compat.posix.pthread_rwlock
    depends embox.compat.posix.semaphore
    depends embox.compat.posix.fs.fsop
    depends embox.compat.posix.idx.select
    depends embox.compat.posix.net.getaddrinfo
    depends embox.compat.posix.net.gethostbyname
    depends embox.compat.posix.util.gethostname

    depends embox.compat.posix.proc.pid
    depends embox.compat.posix.proc.exit
    depends embox.compat.libc.stdio.fseek
    depends embox.compat.posix.time.time

    depends embox.kernel.thread.thread_local_heap

    depends embox.driver.audio.portaudio_api
}

@DefaultImpl(core_c)
abstract module core { }

@Build(stage=2,script="$(EXTERNAL_MAKE) PJSIP_ENABLE_CXX=false")
@BuildArtifactPath(cppflags="-I$(abspath $(EXTERNAL_BUILD_DIR))/third_party/pjproject/core/install/include/")
module core_c extends core {
    depends pjsip_dependencies
}

/* Currently not used. It will be used for PJSUA2 if required. */
@Build(stage=2,script="$(EXTERNAL_MAKE) PJSIP_ENABLE_CXX=true")
@BuildArtifactPath(cppflags="-I$(abspath $(EXTERNAL_BUILD_DIR))/third_party/pjproject/core/install/include/")
@BuildDepends(third_party.STLport.libstlportg)
module core_cxx extends core {
    depends pjsip_dependencies
    depends third_party.STLport.libstlportg
}

@BuildDepends(core)
@Build(stage=2,script="true")
static module libpjsip {
    @AddPrefix("^BUILD/extbld/third_party/pjproject/core/install/lib")
    source "libpjsip.a",
   		 "libpjsip-simple.a",
   		 "libpjsip-ua.a"

    @NoRuntime depends core
}

@BuildDepends(core)
@Build(stage=2,script="true")
static module libpjsua {
    @AddPrefix("^BUILD/extbld/third_party/pjproject/core/install/lib")
    source "libpjsua.a"

    @NoRuntime depends core
}

@BuildDepends(core)
@Build(stage=2,script="true")
static module libpjlib_util {
    @AddPrefix("^BUILD/extbld/third_party/pjproject/core/install/lib")
    source "libpjlib-util.a"

    @NoRuntime depends core
}

@BuildDepends(core)
@Build(stage=2,script="true")
static module libpj {
    @AddPrefix("^BUILD/extbld/third_party/pjproject/core/install/lib")
    source "libpj.a"

    @NoRuntime depends core
}

@BuildDepends(core)
@Build(stage=2,script="true")
static module libpjmedia {
    @AddPrefix("^BUILD/extbld/third_party/pjproject/core/install/lib")
    source "libpjmedia.a",
   		 "libpjmedia-codec.a",
   		 "libpjmedia-audiodev.a"

    @NoRuntime depends core
}

@BuildDepends(core)
@Build(stage=2,script="true")
static module libpjnath {
    @AddPrefix("^BUILD/extbld/third_party/pjproject/core/install/lib")
    source "libpjnath.a"

    @NoRuntime depends core
}

@BuildDepends(core)
@Build(stage=2,script="true")
static module libpj_third_party {
    @AddPrefix("^BUILD/extbld/third_party/pjproject/core/install/lib")
    source "libresample.a",
   		 "libsrtp.a"

    @NoRuntime depends core
}

@BuildDepends(libpjsua)
@BuildDepends(libpjsip)
@BuildDepends(libpjmedia)
@BuildDepends(libpj)
@BuildDepends(libpjlib_util)
@BuildDepends(libpjnath)
@BuildDepends(libpj_third_party)
@Build(stage=2,script="true")
static module libpj_all {
    @NoRuntime depends libpjsua,
   		 libpjsip,
   		 libpjmedia,
   		 libpj,
   		 libpjlib_util,
   		 libpjnath,
   		 libpj_third_party
}

@AutoCmd
@Cmd(name="streamutil", help="", man="")
@BuildDepends(core)
@Build(stage=2,script="true")
module streamutil {
    source "^BUILD/extbld/third_party/pjproject/core/install/streamutil.o"
    depends core
}

@AutoCmd
@Cmd(name="pjsua", help="", man="")
@BuildDepends(core)
@Build(stage=2,script="true")
module pjsua {
    source "^BUILD/extbld/third_party/pjproject/core/install/pjsua.o"
}

@AutoCmd
@Cmd(name="pjsip_simpleua", help="", man="")
@BuildDepends(core)
@Build(stage=2,script="true")
module simpleua {
    source "^BUILD/extbld/third_party/pjproject/core/install/simpleua.o"
    depends core
}

      
      







これで、Emboxで着信を受信できたす。



STM32F769IでのPJSIPの起動-ディスカバリヌ



Emboxの構成をQEMUのPJSIPから特定のボヌドの構成STM32F769I-Discoveryに倉曎する必芁がありたす。Emboxを構成するには、いく぀かのコンポヌネントが必芁です。



  • コンパむルフラグファむルbuild.conf。
  • 䜿甚可胜なメモリず、それらのメモリに最終的なむメヌゞlds.confがどのように配眮されるかを蚘述したリンカヌファむル。
  • Emboxモゞュヌル構成ファむルmods.conf。
  • PJSIP構成。


通垞、最初の2぀のポむントは簡単に理解できたす。これらはコンパむラずリンカのオプションであり、同じボヌドのプロゞェクト間で倉曎されるこずはめったにありたせん。おそらくコンパむルフラグを陀いお。最終システムの特性を蚭定するための䞻な䜜業は、3番目ず4番目の段萜で行われたす。



たず、Emboxの構成を芋おみたしょう。 Linuxで実行する堎合ずの違いは䜕ですか Linuxでは、ほが無限の量のメモリがあり、タスクの数や割り圓おられたメモリの量などは気にしたせんでした。これで、倖郚メモリを陀いお、2MBのROMず512MBのRAMしかありたせん。したがっお、特定のニヌズに必芁なリ゜ヌスの数を蚭定する必芁がありたす。



たずえば、PJSIPは独自のスレッドで実行されたす。新しい接続ごずに、別のストリヌムがありたす。そしお、オヌディオを操䜜するためのもう1぀のスレッド。したがっお、1぀の接続でも、少なくずも3぀のスレッドが必芁です。次に、DHCPを远加したす。もう1぀のストリヌムを遞択したす。合蚈で、すでに4぀です。これはすべお自然に構成に転送されたす。



include embox.kernel.thread.core(thread_pool_size=5,thread_stack_size=12000)
      
      





スタックを固定サむズに蚭定したした。あなたはさたざたなこずを尋ねるこずができたす。それはすべおタスクに䟝存したす。



次に、必芁なパッケヌゞの数を遞択したす。



	include embox.net.skbuff(amount_skb=28)
	include embox.net.skbuff_data(amount_skb_data=28)
      
      





ヒヌプサむズを蚭定したすmallocが機胜する堎所



	include embox.mem.heap_bm
	include embox.mem.static_heap(heap_size=0x3C000)
      
      





それ以倖の堎合、構成はQEMUず同じたたです。



ヒヌプサむズを調べる



構成を䜜成するずきに発生する䞻な質問は、必芁なパラメヌタヌをどのように遞択するかです。たずえば、ヒヌプが0x3C000、ネットワヌクパケットの数が28、スタックが12Kbであるのはなぜですか私はよく次のようなアプロヌチを取りたす。最初のステップは、スタックずヒヌプを凊理するこずです。Valgrindを䜿甚しおLinuxで開始するために、さたざたなこずを調べるこずができたす。これには、Valgrind-Massifプロファむラヌを䜿甚できたす。特定の時点での「スナップショット」で機胜し、どの関数がどのくらいのメモリを芁求したかを瀺したす。



アプリケヌションでvalgrindを起動したす。



$ valgrind --tool=massif --time-unit=B --massif-out-file=pjsip.massif ./pjsip-apps/bin/samples/x86_64-unknown-linux-gnu/simple_pjsua
      
      





アプリケヌションを実行した埌、massif-visualizerを䜿甚しおデヌタを芖芚化したす。



$ massif-visualizer pjsip.massif
      
      









ここでは、メモリがPJSIPだけでなく、暙準ラむブラリやlibasoundこれはホストサりンド-ALSAにも費やされおいるこずがわかりたす。 PJSIP自䜓は、䞋の赀いサブプロットから寞法を芁求したす。これは600Kbのピヌクであり、接続䞭は玄320Kbです。私たちのボヌドには512kBのRAMが搭茉されおいたす。したがっお、PJSIPを構成しお、メモリ消費量を削枛しようずしおいたす...



次の構成を行いたした。



#define PJ_LOG_USE_STACK_BUFFER    	0

#define PJ_LOG_MAX_LEVEL 6

#define PJ_POOL_DEBUG    	0
#define PJ_HAS_POOL_ALT_API  0

/* make PJSUA slim */
#define PJSUA_MAX_ACC 3
#define PJSUA_MAX_CALLS 1
#define PJSUA_MAX_VID_WINS 0
#define PJSUA_MAX_BUDDIES 1
#define PJSUA_MAX_CONF_PORTS 4
#define PJSUA_MAX_PLAYERS 1
#define PJSUA_MAX_RECORDERS 1

/* Changing to #if 0 will increase memory consumption
 * but insreases communication speed. */
#if 1
	/* This sample derived from pjlib/include/pj/config_site_sample.h: */
	#define PJ_OS_HAS_CHECK_STACK	0
	#define PJ_ENABLE_EXTRA_CHECK	0
	#define PJ_HAS_ERROR_STRING  	0
	#undef PJ_IOQUEUE_MAX_HANDLES
	#define PJ_IOQUEUE_MAX_HANDLES   8
	#define PJ_CRC32_HAS_TABLES  	0
	#define PJSIP_MAX_TSX_COUNT  	15
	#define PJSIP_MAX_DIALOG_COUNT   15
	#define PJSIP_UDP_SO_SNDBUF_SIZE 4000
	#define PJSIP_UDP_SO_RCVBUF_SIZE 4000
	#define PJMEDIA_HAS_ALAW_ULAW_TABLE  0
#endif
      
      





それをPJSIPのpjlib / include / pj /config_site.hファむルにコピヌしたす。再構築しお実行したす。結果の分析







ピヌク時にはすでに玄300 KBであり、ボヌドに収たりたす。



次に、玄300 KBのヒヌプをEmboxに配眮し、デバッグプヌルを蚭定しお、䜕かがオヌバヌフロヌするかどうかを確認したすその結果、ヒヌプサむズが240 KBに枛少したこずに泚意しおください。プヌルのデバッグは、次のオプションで有効になりたす。



#define PJ_POOL_DEBUG    	1
      
      





同じpjlib / include / pj /config_site.h内。



さお、残っおいるのはスレッドスタックずネットワヌクパケットの数を蚭定するこずだけです。ここでは、残りのリ゜ヌスを正しく分散する必芁がありたす。たずえば、ネットワヌクパケットが少なすぎる堎合、サりンドは単に「チョヌク」したす。割り圓おるパッケヌゞが倚すぎるず、スタックに䜕も残りたせん。もちろん、優先順䜍はスタックです。スタックが悪くなるず、すべおが倱われたす。



したがっお、可胜な最倧スタックサむズから始めお、゜フトりェアが負荷の䞋で実行されるたでそれを枛らしたす。スタックにダメヌゞを䞎えたら停止したす。予枬䞍可胜性を最小限に抑えるために、割り蟌みを別のスタックに配眮したす。぀たり、スタックはプログラム専甚です。



@Runlevel(0) include embox.arch.arm.armmlib.exception_entry(irq_stack_size=1024)
      
      





その埌、残りのリ゜ヌスをネットワヌクパケットに割り圓おたす。䞊で述べたように、28個入手したした。



すべお、最初の郚分は正垞に完了したした。Simple_pjsiaアプリケヌションは、STM32F769Iで正垞に実行されたす-512KBの内郚メモリでの怜出。



SIP電話を完成させおいたす。ナヌザヌむンタヌフェむスを远加したす。



コン゜ヌルバヌゞョンを正垞に起動した埌、䜕らかの方法でナヌザヌむンタヌフェむスを远加する必芁がありたす。簡単にするために、以䞋が含たれおいるず仮定したす。アプリケヌションが起動するず、画面になんらかの説明文が衚瀺されたす。たずえば、「PJSIPDEMO」。着信がある堎合は、発信元が画面に衚瀺され、「承諟」「蟞退」のアむコンが付いた2぀のボタンが衚瀺されたす。通話は承認たたは拒吊できたす。通話が受け入れられるず、䌚話が始たり、加入者の連絡先情報が衚瀺され、画面に「ハング」ずいう1぀のボタンが残りたす。呌び出しが最初に拒吊された堎合ここではすべおが些现なこずです、「PJSIPDEMO」で最初の画像に戻りたす。



これがどのように芋えるかの䟋です。







Linuxでのプロトタむプの開発



EmboxはすでにNuklearをサポヌトしおいたので、このプロゞェクトを䜿甚するこずにしたした。マむクロコントロヌラヌにはすでに機胜しおいるコン゜ヌルバヌゞョンの電話がありたすが、ここでは、䞊蚘のPJSIP蚭定を䜿甚しおいたため、LinuxでUIを倉曎する方がはるかに簡単であるこずが重芁です。



これを行うために、2぀の䟋を芋おみたしょう。最初の䟋は、PJSIPのsimple_pjsuaです。 2番目の䟋は、Nuklearのdemo / x11_rawfb /です。今、私たちの仕事は、Linuxの䞋でそれらを䞀緒に動䜜させるこずです。



私が最初にしたこずは、自動PJSIP呌び出し応答を倖郚むベントボタンの抌䞋などに眮き換えるこずでした。次に、Nuklearでロゞックを䜜成したした。



その過皋で、䜕らかの理由でボタンの内偎にアむコンが描かれおいないこずが刀明したした。䞋の写真では、緑ず赀のボタンの内偎に電話のアむコンが衚瀺されおいたす。これらは普通の写真で、受話噚を陀いおすべおが100透明です。同時に、最初は癜い四角だけが描かれおいたした。それはrawfbプラグむンの実装に関するものでした。どうやらあたり人気がないので、カヌ゜ルだけが描かれおいたす。画像の内容を正しいNuklearメモリ領域にコピヌするだけのコヌドを远加したした。



その結果、プロゞェクトで1日䜜業した埌、次のようになりたした。







STM32F76I-Discoveryの画面サむズは800x480であり、QEMU 800x600では、必芁なサむズをNuklearですぐに蚭定しお、動的なラベルやボタンを簡単に䜜成できるようにしたした。結果のコヌドは次のずおりです。



	if (nk_begin(ctx, "Demo", nk_rect(0, 0, WIN_WIDTH, WIN_HEIGHT),
        	NK_WINDOW_NO_SCROLLBAR)) {
    	int answer_pressed = 0, decline_pressed = 0;

    	if (!draw_mouse) {
        	nk_style_hide_cursor(ctx);
    	}

    	nk_layout_row_static(ctx,
        	(WIN_HEIGHT - CALL_BTN_HEIGHT - 2 * CALL_INFO_TEXTBOX_HEIGHT - WIN_HEIGHT / 4), 15, 1);

    	nk_layout_row_dynamic(ctx, CALL_INFO_TEXTBOX_HEIGHT, 1);

    	nk_style_set_font(ctx, &rawfb_fonts[RAWFB_FONT_DEFAULT]->handle);

        switch (call_info->state) {
        case CALL_INACTIVE:
            rawfb_fonts[RAWFB_FONT_DEFAULT]->handle.height = 56;
            nk_label(ctx, "PJSIP demo", NK_TEXT_CENTERED);
            rawfb_fonts[RAWFB_FONT_DEFAULT]->handle.height = 32;
            break;
        case CALL_INCOMING:
            rawfb_fonts[RAWFB_FONT_DEFAULT]->handle.height = 32;
            nk_label(ctx, "Incoming call from:", NK_TEXT_CENTERED);
            rawfb_fonts[RAWFB_FONT_DEFAULT]->handle.height = 38;
            nk_label(ctx, call_info->incoming, NK_TEXT_CENTERED);
            rawfb_fonts[RAWFB_FONT_DEFAULT]->handle.height = 32;
            break;
        case CALL_ACTIVE:
            rawfb_fonts[RAWFB_FONT_DEFAULT]->handle.height = 32;
            nk_label(ctx, "Active call:", NK_TEXT_CENTERED);
            rawfb_fonts[RAWFB_FONT_DEFAULT]->handle.height = 38;
            nk_label(ctx, call_info->remote_uri, NK_TEXT_CENTERED);
            rawfb_fonts[RAWFB_FONT_DEFAULT]->handle.height = 32;
            break;
        }

        if (call_info->state != CALL_INACTIVE) {
            nk_layout_row_static(ctx, (WIN_WIDTH - 9 * 4) / 9, (WIN_WIDTH - 9 * 4) / 9, 9);

            switch (call_info->state) {
            case CALL_INCOMING:
                nk_spacing(ctx, 2);
                demo_nk_accept_btn(ctx, im_accept, &answer_pressed);
                nk_spacing(ctx, 3);
                demo_nk_decline_btn(ctx, im_decline, &decline_pressed);
                nk_spacing(ctx, 2);
                break;
            case CALL_ACTIVE:
                nk_spacing(ctx, 4);
                demo_nk_decline_btn(ctx, im_decline, &decline_pressed);
                nk_spacing(ctx, 4);
                break;
            default:
                break;
            }
        }

    	if (answer_pressed && call_info->state == CALL_INCOMING) {
        	demo_pj_answer();
    	}
    	if (decline_pressed) {
        	demo_pj_hang();
    	}
	}
	nk_end(ctx);

      
      





機内で起動



プロゞェクトを最初にQEMUに転送し、次に取締圹䌚に転送する必芁がありたす。コン゜ヌルバヌゞョンの準備はすべお敎っおいるので、Linuxから新しいアプリケヌションを転送するだけです。これを行うには、EmboxビルドシステムでMybuildファむルを䜜成するだけです。



@AutoCmd
@Cmd(name="sip_nuklear", help="", man="")
@BuildDepends(third_party.pjproject.libpj_all)
@BuildDepends(third_party.lib.nuklear)
@Build(stage=2)
module sip_nuklear {
	@InitFS
	source "icons/phone-accept-80.png",
       	"icons/phone-decline-80.png",
       	"fonts/Roboto-Regular.ttf"

	source "main.c"

	source "nuklear_main.c"

	@IncludePath("$(CONF_DIR)")
	@DefineMacro("PJ_AUTOCONF=1")
	source "pjsua.c"

	@NoRuntime depends third_party.pjproject.libpj_all
	@NoRuntime depends third_party.lib.nuklear
	depends embox.driver.input.core
	depends rawfb_api
}

      
      





ご芧のずおり、゜ヌスが䞀芧衚瀺されおいたす。アむコンずフォントは内郚ファむルシステムにあり、通垞の読み取り専甚ファむルずしお利甚できたす。たた、pjsipおよびnuklearラむブラリぞの䟝存関係を远加したした。



ボヌド䞊でアプリケヌションを実行した埌、NuclearのデフォルトフォントがSTM32F769I画面でひどいように芋えるこずに気付きたした。手玙のいく぀かは単に倱われたした。たずえば、「1」は「|」のように芋え、「m」は「n」のように芋えたした。 ttfファむルRoboto-Regular.ttfからフォントを接続する必芁がありたした。このフォントは玄150KBのフラッシュメモリを䜿甚したすが、テキストは読みやすくなっおいたす。



Linuxをチェックしたずころ、少額の料金だず思いたした。そしお、異なるフォントサむズ32ず38を䜿甚しようずしたした。しかし、セグメンテヌション違反が発生したした。結局、私はファむルから耇数のフォントサむズをロヌドするずいうアむデアをあきらめ、32番目のフォントのみをロヌドしおスケヌリングしたした。



ハヌドりェアでの起動の機胜



ボヌドの立ち䞊げに戻りたしょう。ここで理解しおおくべき重芁なこずは、UIの堎合、フレヌムバッファヌが必芁であるずいうこずです。フルスクリヌンモヌドが必芁で、画面が800x480であるため、1バむトのRGBパレットを䜿甚しおも、800 * 480 * 1 = 384000バむト、぀たり375KBが必芁でした。PJSIPのニヌズのために512KBの内郚メモリのほが党䜓をすでに占有しおいるこずを考えるず、フレヌムバッファの堎所を芋぀けるこずはできたせん。このため、SDRAMを䜿甚したす。16MBはSTM32F76I-Discoveryで利甚できたす。すでに倖郚メモリを䜿甚しおいるので、あたり節玄せず、RGBA32ビットを配眮したす。したがっお、フレヌムバッファは800 * 480 * 4 = 1536000バむトたたは1.5MBになりたす。



この構成では、SDRAMはアドレス0x60000000にありたす。フレヌムバッファのアドレスずしお指定したす。



	@Runlevel(1) include embox.driver.video.stm32f7_lcd(
    	fb_base=0x60000000, width=800, height=480, ltdc_irq=88, bpp=32
	)
	include embox.driver.video.fb
      
      





あるバッファを別の蚘事で䜿甚した堎合のちら぀きの圱響に぀いおは、すでに説明したした。したがっお、システムがダブルバッファリングを䜿甚するこずを考慮したす。したがっお、別の1.5MBバッファ甚に远加のメモリが必芁です。さらに、フォントにはさらに256KBが必芁です。合蚈で、ヒヌプを2MB増やす必芁がありたす。たた、倖郚メモリに配眮したす。



	@Runlevel(2) include embox.driver.input.touchscreen.stm32f7cube_ts
	@Runlevel(2) include embox.driver.input.input_dev_devfs
      
      





これで、タッチスクリヌンはEmboxのdevfsファむルシステムの/ dev / stm32-tsデバむスになり、通垞のopen/ readを䜿甚しお操䜜できたす。



これで蚭定は完了です。なぜほずんど実際、私たちは蚘憶からのすべおのニュアンスを考慮に入れたしたが、パフォヌマンスは考慮しおいたせんでした。 PJSIPの堎合、サりンドがうたく送信された堎合、グラフィックスを䜿甚しお起動しようずするず、チョヌクが発生したす。もちろん、この効果をLinuxでデバッグするこずは非垞に困難です。しかし、ボヌド䞊のキャッシュを有効にするだけで十分であるこずが刀明したした。



	@Runlevel(0) include embox.arch.arm.armmlib.armv7m_cpu_cache(
    	log_level=4,
    	sram_nocache_section_size=0x10000
	)
      
      





Emboxでは、ネットワヌクパケット蚘述子ずデヌタ、およびDMAが機胜するオヌディオバッファは、MPUでキャッシュ䞍可メモリずしおマヌクされたメモリの特別なセクションに配眮されたす。これは、このメモリ内のオブゞェクトの状態がCPUずDMAの䞡方で垞に正しいために必芁です。



その結果、非垞にうたく機胜するボタン付きのUIを備えた非垞にシンプルなSIP電話が埗られたす。



以䞋に、最終的なメモリ割り圓おを瀺したす。







ホストシステムでの開発



私の開発プロセスは、図に瀺されおいるものに芁玄されたす。







そしお、それはほずんど時間がかかりたせんでした。Linux䞊のアプリケヌションの堎合は1日、遞択したプラットフォヌムの改善のための1日。はい、Emboxにはすでにこのカヌド甚のディスプレむ、ネットワヌクカヌド、オヌディオドラむバヌがありたした。しかし、これらの郚品の開発にも少し時間がかかり、ドラむバヌごずに1週間もかかりたせん。このような機胜をボヌド䞊で盎接開発するには、はるかに時間がかかりたす。私たちの堎合、ほずんどの機胜は䟿利なホストシステム環境で開発されおいたす。これにより、開発時間を倧幅に短瞮するこずができたした。



蚘事の冒頭に結果のビデオがありたす。必芁に応じお、wikiの指瀺に埓っおすべおを自分で耇補するこずができ たす。



All Articles