[-]
[+]
|
Changed |
_service:tar_git:libgbinder-radio.changes
|
|
[-]
[+]
|
Changed |
_service:tar_git:libgbinder-radio.spec
^
|
|
[-]
[+]
|
Changed |
_service
^
|
@@ -2,7 +2,7 @@
<service name="tar_git">
<param name="url">https://github.com/mer-hybris/libgbinder-radio.git</param>
<param name="branch">master</param>
- <param name="revision">1.4.1</param>
+ <param name="revision">1.5.4</param>
<param name="token"/>
<param name="debian"/>
<param name="dumb"/>
|
[-]
[+]
|
Changed |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/.gitignore
^
|
@@ -8,6 +8,8 @@
debian/*.install
debian/tmp
documentation.list
+unit/coverage/*.gcov
+unit/coverage/report
installroot
build
RPMS
|
[-]
[+]
|
Changed |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/LICENSE
^
|
@@ -1,5 +1,5 @@
-Copyright (C) 2018-2021 Jolla Ltd.
-Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
+Copyright (C) 2018-2022 Jolla Ltd.
+Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
You may use this file under the terms of the BSD license as follows:
|
[-]
[+]
|
Changed |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/Makefile
^
|
@@ -1,7 +1,8 @@
# -*- Mode: makefile-gmake -*-
-.PHONY: clean all debug release coverage
+.PHONY: clean all debug release coverage test
.PHONY: debug_lib release_lib coverage_lib
+.PHONY: print_debug_lib print_release_lib print_coverage_lib
.PHONY: pkgconfig install install-dev
@@ -22,8 +23,8 @@
#
VERSION_MAJOR = 1
-VERSION_MINOR = 4
-VERSION_RELEASE = 1
+VERSION_MINOR = 5
+VERSION_RELEASE = 4
# Version for pkg-config
PCVERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
@@ -46,8 +47,13 @@
#
SRC = \
+ radio_base.c \
+ radio_client.c \
+ radio_config.c \
radio_instance.c \
radio_registry.c \
+ radio_request.c \
+ radio_request_group.c \
radio_util.c
#
@@ -138,7 +144,17 @@
pkgconfig: $(PKGCONFIG)
+print_debug_lib:
+ @echo $(DEBUG_LIB)
+
+print_release_lib:
+ @echo $(RELEASE_LIB)
+
+print_coverage_lib:
+ @echo $(COVERAGE_LIB)
+
clean:
+ make -C unit clean
rm -f *~ $(SRC_DIR)/*~ $(INCLUDE_DIR)/*~
rm -fr $(BUILD_DIR) RPMS installroot
rm -fr debian/tmp debian/libgbinder-radio debian/libgbinder-radio-dev
@@ -146,6 +162,9 @@
rm -f debian/*.debhelper.log debian/*.debhelper debian/*~
rm -f debian/*.install
+test:
+ make -C unit test
+
$(BUILD_DIR):
mkdir -p $@
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/README
^
|
@@ -0,0 +1,2 @@
+A library for communicating with Android IRadio binder services,
+built on top of libgbinder.
|
[-]
[+]
|
Changed |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/debian/changelog
^
|
@@ -1,3 +1,101 @@
+libgbinder-radio (1.5.4) unstable; urgency=medium
+
+ * Added NR specific types
+
+ -- Slava Monich <slava.monich@jolla.com> Wed, 30 Nov 2022 19:14:38 +0200
+
+libgbinder-radio (1.5.3) unstable; urgency=medium
+
+ * Added RADIO_ACCESS_NETWORKS enum
+
+ -- Slava Monich <slava.monich@jolla.com> Sat, 19 Nov 2022 17:48:38 +0200
+
+libgbinder-radio (1.5.2) unstable; urgency=medium
+
+ * Added network scan related types
+
+ -- Slava Monich <slava.monich@jolla.com> Thu, 17 Nov 2022 03:12:02 +0200
+
+libgbinder-radio (1.5.1) unstable; urgency=medium
+
+ * Fixed names of IRadio 1.4 and 1.5 responses
+
+ -- Slava Monich <slava.monich@jolla.com> Mon, 14 Nov 2022 22:34:08 +0200
+
+libgbinder-radio (1.5.0) unstable; urgency=medium
+
+ * Added support for IRadio@1.5
+ * Added support for IRadioConfig@1.2
+
+ -- Slava Monich <slava.monich@jolla.com> Fri, 16 Sep 2022 14:13:04 +0300
+
+libgbinder-radio (1.4.12) unstable; urgency=medium
+
+ * Fixed RadioDataRegStateResult_1_4
+
+ -- Slava Monich <slava.monich@jolla.com> Sun, 11 Sep 2022 21:37:23 +0300
+
+libgbinder-radio (1.4.11) unstable; urgency=medium
+
+ * Added radio_request_user_data()
+
+ -- Slava Monich <slava.monich@jolla.com> Wed, 31 Aug 2022 19:10:49 +0300
+
+libgbinder-radio (1.4.10) unstable; urgency=medium
+
+ * Tweaked completion callback criteria
+
+ -- Slava Monich <slava.monich@jolla.com> Fri, 15 Apr 2022 21:58:17 +0300
+
+libgbinder-radio (1.4.9) unstable; urgency=medium
+
+ * Added IMS types
+
+ -- Slava Monich <slava.monich@jolla.com> Thu, 17 Feb 2022 01:47:27 +0200
+
+libgbinder-radio (1.4.8) unstable; urgency=medium
+
+ * Fixed retries of blocking requests
+
+ -- Slava Monich <slava.monich@jolla.com> Wed, 19 Jan 2022 03:32:30 +0200
+
+libgbinder-radio (1.4.7) unstable; urgency=medium
+
+ * Fixed owner queue logic
+
+ -- Slava Monich <slava.monich@jolla.com> Mon, 10 Jan 2022 01:03:28 +0200
+
+libgbinder-radio (1.4.6) unstable; urgency=medium
+
+ * Added RadioConfig API
+
+ -- Slava Monich <slava.monich@jolla.com> Sat, 08 Jan 2022 20:58:06 +0200
+
+libgbinder-radio (1.4.5) unstable; urgency=medium
+
+ * Added radio_req_resp2()
+
+ -- Slava Monich <slava.monich@jolla.com> Thu, 16 Dec 2021 01:18:54 +0200
+
+libgbinder-radio (1.4.4) unstable; urgency=medium
+
+ * Added IRadio@1.2 IndicationFilter bits
+
+ -- Slava Monich <slava.monich@jolla.com> Tue, 14 Dec 2021 18:01:43 +0200
+
+libgbinder-radio (1.4.3) unstable; urgency=medium
+
+ * Added RadioClient and related APIs
+
+ -- Slava Monich <slava.monich@jolla.com> Thu, 02 Dec 2021 19:08:47 +0200
+
+libgbinder-radio (1.4.2) unstable; urgency=medium
+
+ * Don't assume that GBinderServiceManager is a GObject
+ * Added unit tests
+
+ -- Slava Monich <slava.monich@jolla.com> Sun, 12 Sep 2021 18:05:19 +0300
+
libgbinder-radio (1.4.1) unstable; urgency=medium
* Added RADIO_CELL_INFO_TYPE_1_4 enum
|
[-]
[+]
|
Changed |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/debian/control
^
|
@@ -1,7 +1,7 @@
Source: libgbinder-radio
Priority: optional
Maintainer: Danct12 <danct12@disroot.org>
-Build-Depends: debhelper (>=9), libgbinder-dev (>= 1.0.9)
+Build-Depends: debhelper (>=9), libgbinder-dev (>= 1.1.14), libglibutil-dev (>= 1.0.49)
Standards-Version: 3.9.6
Package: libgbinder-radio-dev
@@ -13,5 +13,5 @@
Package: libgbinder-radio
Section: libs
Architecture: any
-Depends: libgbinder (>= 1.0.9), ${shlibs:Depends}, ${misc:Depends}
+Depends: libgbinder (>= 1.1.14), libglibutil (>= 1.0.49), ${shlibs:Depends}, ${misc:Depends}
Description: Binder client library for Android radio interfaces
|
[-]
[+]
|
Changed |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/debian/copyright
^
|
@@ -1,5 +1,5 @@
-Copyright (C) 2018-2021 Jolla Ltd.
-Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
+Copyright (C) 2018-2022 Jolla Ltd.
+Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
You may use this file under the terms of the BSD license as follows:
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/include/radio_client.h
^
|
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2021 Jolla Ltd.
+ * Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#ifndef RADIO_CLIENT_H
+#define RADIO_CLIENT_H
+
+/* This API exists since 1.4.3 */
+
+#include <radio_types.h>
+
+G_BEGIN_DECLS
+
+typedef
+void
+(*RadioClientIndicationFunc)(
+ RadioClient* client,
+ RADIO_IND code,
+ const GBinderReader* reader,
+ gpointer user_data);
+
+typedef
+void
+(*RadioClientFunc)(
+ RadioClient* client,
+ gpointer user_data);
+
+RadioClient*
+radio_client_new(
+ RadioInstance* instance)
+ G_GNUC_WARN_UNUSED_RESULT;
+
+RadioClient*
+radio_client_ref(
+ RadioClient* client);
+
+void
+radio_client_unref(
+ RadioClient* client);
+
+RADIO_INTERFACE
+radio_client_interface(
+ RadioClient* client);
+
+const char*
+radio_client_slot(
+ RadioClient* client);
+
+gboolean
+radio_client_dead(
+ RadioClient* client);
+
+gboolean
+radio_client_connected(
+ RadioClient* client);
+
+void
+radio_client_set_default_timeout(
+ RadioClient* client,
+ int milliseconds);
+
+gulong
+radio_client_add_indication_handler(
+ RadioClient* client,
+ RADIO_IND code,
+ RadioClientIndicationFunc func,
+ gpointer user_data);
+
+gulong
+radio_client_add_owner_changed_handler(
+ RadioClient* client,
+ RadioClientFunc func,
+ gpointer user_data);
+
+gulong
+radio_client_add_death_handler(
+ RadioClient* client,
+ RadioClientFunc func,
+ gpointer user_data);
+
+gulong
+radio_client_add_connected_handler(
+ RadioClient* client,
+ RadioClientFunc func,
+ gpointer user_data);
+
+void
+radio_client_remove_handler(
+ RadioClient* client,
+ gulong id);
+
+void
+radio_client_remove_handlers(
+ RadioClient* client,
+ gulong* ids,
+ int count);
+
+#define radio_client_remove_all_handlers(client,ids) \
+ radio_client_remove_handlers(client, ids, G_N_ELEMENTS(ids))
+
+G_END_DECLS
+
+#endif /* RADIO_CLIENT_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/include/radio_config.h
^
|
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2022 Jolla Ltd.
+ * Copyright (C) 2022 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#ifndef RADIO_CONFIG_H
+#define RADIO_CONFIG_H
+
+/* This API exists since 1.4.6 */
+
+#include <radio_config_types.h>
+
+G_BEGIN_DECLS
+
+typedef
+void
+(*RadioConfigFunc)(
+ RadioConfig* config,
+ gpointer user_data);
+
+typedef
+void
+(*RadioConfigRequestObserverFunc)(
+ RadioConfig* config,
+ RADIO_CONFIG_REQ code,
+ GBinderLocalRequest* args,
+ gpointer user_data);
+
+typedef
+void
+(*RadioConfigResponseObserverFunc)(
+ RadioConfig* config,
+ RADIO_CONFIG_RESP code,
+ const RadioResponseInfo* info,
+ const GBinderReader* args,
+ gpointer user_data);
+
+typedef
+void
+(*RadioConfigIndicationObserverFunc)(
+ RadioConfig* config,
+ RADIO_CONFIG_IND code,
+ const GBinderReader* args,
+ gpointer user_data);
+
+RadioConfig*
+radio_config_new(void)
+ G_GNUC_WARN_UNUSED_RESULT;
+
+RadioConfig*
+radio_config_new_with_version(
+ RADIO_CONFIG_INTERFACE max_version)
+ G_GNUC_WARN_UNUSED_RESULT;
+
+RadioConfig*
+radio_config_ref(
+ RadioConfig* config);
+
+void
+radio_config_unref(
+ RadioConfig* config);
+
+gboolean
+radio_config_dead(
+ RadioConfig* config);
+
+RADIO_CONFIG_INTERFACE
+radio_config_interface(
+ RadioConfig* config);
+
+gsize
+radio_config_rpc_header_size(
+ RadioConfig* config,
+ RADIO_CONFIG_REQ req);
+
+const char*
+radio_config_req_name(
+ RadioConfig* config,
+ RADIO_CONFIG_REQ req);
+
+const char*
+radio_config_resp_name(
+ RadioConfig* config,
+ RADIO_CONFIG_RESP resp);
+
+const char*
+radio_config_ind_name(
+ RadioConfig* config,
+ RADIO_CONFIG_IND ind);
+
+gulong
+radio_config_add_death_handler(
+ RadioConfig* config,
+ RadioConfigFunc func,
+ gpointer user_data);
+
+gulong
+radio_config_add_request_observer(
+ RadioConfig* config,
+ RADIO_CONFIG_REQ code,
+ RadioConfigRequestObserverFunc func,
+ gpointer user_data);
+
+gulong
+radio_config_add_request_observer_with_priority(
+ RadioConfig* config,
+ RADIO_OBSERVER_PRIORITY priority,
+ RADIO_CONFIG_REQ code,
+ RadioConfigRequestObserverFunc func,
+ gpointer user_data);
+
+gulong
+radio_config_add_response_observer(
+ RadioConfig* config,
+ RADIO_CONFIG_RESP code,
+ RadioConfigResponseObserverFunc func,
+ gpointer user_data);
+
+gulong
+radio_config_add_response_observer_with_priority(
+ RadioConfig* config,
+ RADIO_OBSERVER_PRIORITY priority,
+ RADIO_CONFIG_RESP code,
+ RadioConfigResponseObserverFunc func,
+ gpointer user_data);
+
+gulong
+radio_config_add_indication_observer(
+ RadioConfig* config,
+ RADIO_CONFIG_IND code,
+ RadioConfigIndicationObserverFunc func,
+ gpointer user_data);
+
+gulong
+radio_config_add_indication_observer_with_priority(
+ RadioConfig* config,
+ RADIO_OBSERVER_PRIORITY priority,
+ RADIO_CONFIG_IND code,
+ RadioConfigIndicationObserverFunc func,
+ gpointer user_data);
+
+void
+radio_config_remove_handler(
+ RadioConfig* config,
+ gulong id);
+
+void
+radio_config_remove_handlers(
+ RadioConfig* config,
+ gulong* ids,
+ int count);
+
+#define radio_config_remove_all_handlers(config,ids) \
+ radio_config_remove_handlers(config, ids, G_N_ELEMENTS(ids))
+
+G_END_DECLS
+
+#endif /* RADIO_CONFIG_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/include/radio_config_types.h
^
|
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2022 Jolla Ltd.
+ * Copyright (C) 2022 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#ifndef RADIO_CONFIG_TYPES_H
+#define RADIO_CONFIG_TYPES_H
+
+/* This API exists since 1.4.6 */
+
+#include <radio_types.h>
+
+G_BEGIN_DECLS
+
+typedef enum radio_config_interface {
+ RADIO_CONFIG_INTERFACE_NONE = -1,
+ RADIO_CONFIG_INTERFACE_1_0,
+ RADIO_CONFIG_INTERFACE_1_1,
+ RADIO_CONFIG_INTERFACE_1_2, /* Since 1.5.0 */
+ RADIO_CONFIG_INTERFACE_COUNT
+} RADIO_CONFIG_INTERFACE;
+
+#define RADIO_CONFIG_INTERFACE_MAX (RADIO_CONFIG_INTERFACE_COUNT - 1)
+
+#define RADIO_CONFIG_INSTANCE "default"
+#define RADIO_CONFIG_IFACE_PREFIX "android.hardware.radio.config@"
+#define RADIO_CONFIG_IFACE "IRadioConfig"
+#define RADIO_CONFIG_RESPONSE_IFACE "IRadioConfigResponse"
+#define RADIO_CONFIG_INDICATION_IFACE "IRadioConfigIndication"
+#define RADIO_CONFIG_IFACE_1_0(x) RADIO_CONFIG_IFACE_PREFIX "1.0::" x
+#define RADIO_CONFIG_IFACE_1_1(x) RADIO_CONFIG_IFACE_PREFIX "1.1::" x
+#define RADIO_CONFIG_IFACE_1_2(x) RADIO_CONFIG_IFACE_PREFIX "1.2::" x
+#define RADIO_CONFIG_1_0 RADIO_CONFIG_IFACE_1_0(RADIO_CONFIG_IFACE)
+#define RADIO_CONFIG_1_1 RADIO_CONFIG_IFACE_1_1(RADIO_CONFIG_IFACE)
+#define RADIO_CONFIG_1_2 RADIO_CONFIG_IFACE_1_2(RADIO_CONFIG_IFACE)
+#define RADIO_CONFIG_1_0_FQNAME RADIO_CONFIG_1_0 "/" RADIO_CONFIG_INSTANCE
+#define RADIO_CONFIG_1_1_FQNAME RADIO_CONFIG_1_1 "/" RADIO_CONFIG_INSTANCE
+#define RADIO_CONFIG_1_2_FQNAME RADIO_CONFIG_1_2 "/" RADIO_CONFIG_INSTANCE
+#define RADIO_CONFIG_RESPONSE_1_0 \
+ RADIO_CONFIG_IFACE_1_0(RADIO_CONFIG_RESPONSE_IFACE)
+#define RADIO_CONFIG_RESPONSE_1_1 \
+ RADIO_CONFIG_IFACE_1_1(RADIO_CONFIG_RESPONSE_IFACE)
+#define RADIO_CONFIG_RESPONSE_1_2 \
+ RADIO_CONFIG_IFACE_1_2(RADIO_CONFIG_RESPONSE_IFACE)
+#define RADIO_CONFIG_INDICATION_1_0 \
+ RADIO_CONFIG_IFACE_1_0(RADIO_CONFIG_INDICATION_IFACE)
+#define RADIO_CONFIG_INDICATION_1_1 \
+ RADIO_CONFIG_IFACE_1_1(RADIO_CONFIG_INDICATION_IFACE)
+#define RADIO_CONFIG_INDICATION_1_2 \
+ RADIO_CONFIG_IFACE_1_2(RADIO_CONFIG_INDICATION_IFACE)
+
+/* Types defined in types.hal */
+
+/* SlotState */
+typedef enum radio_slot_state {
+ RADIO_SLOT_STATE_INACTIVE,
+ RADIO_SLOT_STATE_ACTIVE
+} RADIO_SLOT_STATE;
+G_STATIC_ASSERT(sizeof(RADIO_SLOT_STATE) == 4);
+
+/* SimSlotStatus */
+typedef struct radio_sim_slot_status {
+ RADIO_CARD_STATE cardState RADIO_ALIGNED(4);
+ RADIO_SLOT_STATE slotState RADIO_ALIGNED(4);
+ GBinderHidlString atr RADIO_ALIGNED(8);
+ guint32 logicalSlotId RADIO_ALIGNED(4);
+ GBinderHidlString iccid RADIO_ALIGNED(8);
+} RADIO_ALIGNED(8) RadioSimSlotStatus;
+G_STATIC_ASSERT(sizeof(RadioSimSlotStatus) == 48);
+
+/* ModemInfo */
+typedef struct radio_modem_info {
+ guint8 modemId RADIO_ALIGNED(1);
+} RADIO_ALIGNED(1) RadioModemInfo;
+G_STATIC_ASSERT(sizeof(RadioModemInfo) == 1);
+
+/* PhoneCapability */
+typedef struct radio_phone_capability {
+ guint8 maxActiveData RADIO_ALIGNED(1);
+ guint8 maxActiveInternetData RADIO_ALIGNED(1);
+ guint8 isInternetLingeringSupported RADIO_ALIGNED(1);
+ GBinderHidlVec logicalModemList RADIO_ALIGNED(8); /* vec<ModemInfo> */
+} RADIO_ALIGNED(8) RadioPhoneCapability;
+G_STATIC_ASSERT(sizeof(RadioPhoneCapability) == 24);
+
+/* ModemsConfig */
+typedef struct radio_modems_config {
+ guint8 numOfLiveModems RADIO_ALIGNED(1);
+} RADIO_ALIGNED(1) RadioModemsConfig;
+G_STATIC_ASSERT(sizeof(RadioModemsConfig) == 1);
+
+/* Transaction codes */
+
+/* c(req,resp,Name,CALL_NAME) */
+#define RADIO_CONFIG_CALL_1_0(c) \
+ c(2,1,getSimSlotsStatus,GET_SIM_SLOTS_STATUS) \
+ c(3,2,setSimSlotsMapping,SET_SIM_SLOTS_MAPPING)
+
+#define RADIO_CONFIG_CALL_1_1(c) \
+ c(4,3,getPhoneCapability,GET_PHONE_CAPABILITY) \
+ c(5,4,setPreferredDataModem,SET_PREFERRED_DATA_MODEM) \
+ c(6,5,setModemsConfig,SET_MODEMS_CONFIG) \
+ c(7,6,getModemsConfig,GET_MODEMS_CONFIG)
+
+/* i(code,Name,IND_NAME) */
+#define RADIO_CONFIG_IND_1_0(i) \
+ i(1,simSlotsStatusChanged,SIM_SLOTS_STATUS_CHANGED)
+
+#define RADIO_CONFIG_IND_1_2(i) \
+ i(2,simSlotsStatusChanged_1_2,SIM_SLOTS_STATUS_CHANGED_1_2) /* Since 1.5.0 */
+
+typedef enum radio_config_req {
+ RADIO_CONFIG_REQ_ANY = 0,
+ RADIO_CONFIG_REQ_NONE = 0,
+#define RADIO_CONFIG_REQ_(req,resp,Name,NAME) RADIO_CONFIG_REQ_##NAME = req,
+
+ /* android.hardware.radio.config@1.0::IRadioConfig */
+ RADIO_CONFIG_REQ_SET_RESPONSE_FUNCTIONS = 1, /* setResponseFunctions */
+ RADIO_CONFIG_CALL_1_0(RADIO_CONFIG_REQ_)
+ RADIO_CONFIG_1_0_REQ_LAST = RADIO_CONFIG_REQ_SET_SIM_SLOTS_MAPPING,
+
+ /* android.hardware.radio.config@1.1::IRadioConfig */
+ RADIO_CONFIG_CALL_1_1(RADIO_CONFIG_REQ_)
+ RADIO_CONFIG_1_1_REQ_LAST = RADIO_CONFIG_REQ_GET_MODEMS_CONFIG
+
+#undef RADIO_CONFIG_REQ_
+} RADIO_CONFIG_REQ;
+G_STATIC_ASSERT(sizeof(RADIO_CONFIG_REQ) == 4);
+
+typedef enum radio_config_resp {
+ RADIO_CONFIG_RESP_ANY = 0,
+ RADIO_CONFIG_RESP_NONE = 0,
+#define RADIO_CONFIG_RESP_(req,resp,Name,NAME) RADIO_CONFIG_RESP_##NAME = resp,
+
+ /* android.hardware.radio.config@1.0::IRadioConfigResponse */
+ RADIO_CONFIG_CALL_1_0(RADIO_CONFIG_RESP_)
+ RADIO_CONFIG_1_0_RESP_LAST = RADIO_CONFIG_RESP_SET_SIM_SLOTS_MAPPING,
+
+ /* android.hardware.radio.config@1.1::IRadioConfigResponse */
+ RADIO_CONFIG_CALL_1_1(RADIO_CONFIG_RESP_)
+ RADIO_CONFIG_1_1_RESP_LAST = RADIO_CONFIG_RESP_GET_MODEMS_CONFIG,
+
+ /* android.hardware.radio.config@1.2::IRadioConfigResponse */
+ RADIO_CONFIG_RESP_GET_SIM_SLOTS_STATUS_1_2 = 7, /* Since 1.5.0 */
+ RADIO_CONFIG_1_2_RESP_LAST = RADIO_CONFIG_RESP_GET_SIM_SLOTS_STATUS_1_2
+#undef RADIO_CONFIG_RESP_
+} RADIO_CONFIG_RESP;
+G_STATIC_ASSERT(sizeof(RADIO_CONFIG_RESP) == 4);
+
+typedef enum radio_config_ind {
+ RADIO_CONFIG_IND_ANY = 0,
+ RADIO_CONFIG_IND_NONE = 0,
+#define RADIO_CONFIG_IND_(code,Name,NAME) RADIO_CONFIG_IND_##NAME = code,
+
+ /* android.hardware.radio.config@1.0::IRadioConfigIndication */
+ RADIO_CONFIG_IND_1_0(RADIO_CONFIG_IND_)
+ RADIO_CONFIG_1_0_IND_LAST = RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED,
+
+ /* android.hardware.radio.config@1.2::IRadioConfigIndication */
+ RADIO_CONFIG_IND_1_2(RADIO_CONFIG_IND_) /* Since 1.5.0 */
+ RADIO_CONFIG_1_2_IND_LAST = RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED_1_2
+#undef RADIO_CONFIG_IND_
+} RADIO_CONFIG_IND;
+G_STATIC_ASSERT(sizeof(RADIO_CONFIG_IND) == 4);
+
+G_END_DECLS
+
+#endif /* RADIO_CONFIG_TYPES_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Changed |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/include/radio_instance.h
^
|
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2018-2021 Jolla Ltd.
- * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
+ * Copyright (C) 2018-2022 Jolla Ltd.
+ * Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
@@ -45,15 +45,6 @@
typedef struct radio_instance_priv RadioInstancePriv;
-typedef enum radio_interface {
- RADIO_INTERFACE_1_0,
- RADIO_INTERFACE_1_1,
- RADIO_INTERFACE_1_2,
- RADIO_INTERFACE_1_3,
- RADIO_INTERFACE_1_4,
- RADIO_INTERFACE_COUNT
-} RADIO_INTERFACE; /* Since 1.2.0 */
-
struct radio_instance {
GObject parent;
RadioInstancePriv* priv;
@@ -67,8 +58,16 @@
gboolean enabled;
/* Since 1.2.0 */
RADIO_INTERFACE version;
+ /* Since 1.4.3 */
+ gboolean connected; /* rilConnected received */
};
+/* These were introduced in 1.4.3 and then renamed in 1.4.6 */
+#define RADIO_INSTANCE_PRIORITY_LOWEST RADIO_OBSERVER_PRIORITY_LOWEST
+#define RADIO_INSTANCE_PRIORITY_DEFAULT RADIO_OBSERVER_PRIORITY_DEFAULT
+#define RADIO_INSTANCE_PRIORITY_HIGHEST RADIO_OBSERVER_PRIORITY_HIGHEST
+#define RADIO_INSTANCE_PRIORITY RADIO_OBSERVER_PRIORITY
+
typedef
void
(*RadioInstanceFunc)(
@@ -76,6 +75,14 @@
gpointer user_data);
typedef
+void
+(*RadioRequestObserverFunc)(
+ RadioInstance* radio,
+ RADIO_REQ code,
+ GBinderLocalRequest* args,
+ gpointer user_data); /* Since 1.4.3 */
+
+typedef
gboolean
(*RadioResponseHandlerFunc)(
RadioInstance* radio,
@@ -172,6 +179,11 @@
radio_instance_unref(
RadioInstance* radio);
+gsize
+radio_instance_rpc_header_size(
+ RadioInstance* radio,
+ RADIO_REQ req); /* Since 1.4.3 */
+
const char*
radio_instance_req_name(
RadioInstance* radio,
@@ -208,13 +220,36 @@
gboolean enabled); /* Since 1.0.7 */
gulong
-radio_instance_add_indication_handler(
+radio_instance_add_request_observer(
RadioInstance* radio,
- RADIO_IND code,
- RadioIndicationHandlerFunc func,
+ RADIO_REQ code,
+ RadioRequestObserverFunc func,
+ gpointer user_data); /* Since 1.4.3 */
+
+gulong
+radio_instance_add_request_observer_with_priority(
+ RadioInstance* radio,
+ RADIO_OBSERVER_PRIORITY priority,
+ RADIO_REQ code,
+ RadioRequestObserverFunc func,
+ gpointer user_data); /* Since 1.4.3 */
+
+gulong
+radio_instance_add_response_observer(
+ RadioInstance* radio,
+ RADIO_RESP code,
+ RadioResponseObserverFunc func,
gpointer user_data);
gulong
+radio_instance_add_response_observer_with_priority(
+ RadioInstance* radio,
+ RADIO_OBSERVER_PRIORITY priority,
+ RADIO_RESP code,
+ RadioResponseObserverFunc func,
+ gpointer user_data); /* Since 1.4.3 */
+
+gulong
radio_instance_add_indication_observer(
RadioInstance* radio,
RADIO_IND code,
@@ -222,6 +257,14 @@
gpointer user_data);
gulong
+radio_instance_add_indication_observer_with_priority(
+ RadioInstance* radio,
+ RADIO_OBSERVER_PRIORITY priority,
+ RADIO_IND code,
+ RadioIndicationObserverFunc func,
+ gpointer user_data); /* Since 1.4.3 */
+
+gulong
radio_instance_add_response_handler(
RadioInstance* radio,
RADIO_RESP code,
@@ -229,10 +272,10 @@
gpointer user_data);
gulong
-radio_instance_add_response_observer(
+radio_instance_add_indication_handler(
RadioInstance* radio,
- RADIO_RESP code,
- RadioResponseObserverFunc func,
+ RADIO_IND code,
+ RadioIndicationHandlerFunc func,
gpointer user_data);
gulong
@@ -253,6 +296,12 @@
RadioInstanceFunc func,
gpointer user_data); /* Since 1.0.7 */
+gulong
+radio_instance_add_connected_handler(
+ RadioInstance* radio,
+ RadioInstanceFunc func,
+ gpointer user_data); /* Since 1.4.3 */
+
void
radio_instance_remove_handler(
RadioInstance* radio,
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/include/radio_request.h
^
|
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2021-2022 Jolla Ltd.
+ * Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#ifndef RADIO_REQUEST_H
+#define RADIO_REQUEST_H
+
+/* This API exists since 1.4.3 */
+
+#include <radio_config_types.h>
+
+/*
+ * Basic workflow
+ *
+ * 1. radio_request_new() or radio_request_new2() creates the request.
+ * That assigns a serial and initializes GBinderWriter for appending
+ * more arguments. GBinderWriter pointer can be NULL if serial is the
+ * only argument.
+ * 2. The caller (optionally) uses GBinderWriter to add more arguments
+ * to the request.
+ * 3. radio_request_submit() submits the request
+ * 4. radio_request_unref() can be called at this point to release the
+ * reference produced by radio_request_new() unless the caller needs
+ * to keep it. In any case, radio_request_unref() has to be called
+ * sooner or later for each request created by radio_request_new().
+ * The library keeps its own internal reference while the request is
+ * being processed.
+ * 5. RadioRequestCompleteFunc receives the response from the radio service.
+ */
+
+G_BEGIN_DECLS
+
+typedef enum radio_tx_status {
+ RADIO_TX_STATUS_OK, /* Successful completion, no error */
+ RADIO_TX_STATUS_FAILED, /* Request transaction failed */
+ RADIO_TX_STATUS_TIMEOUT /* No response transaction received */
+} RADIO_TX_STATUS;
+
+/*
+ * RadioRequestCompleteFunc
+ * RadioConfigRequestCompleteFunc
+ *
+ * Invoked upon completion of each request. If an error occurs,
+ * resp is set to zero (RADIO_RESP_NONE, RADIO_CONFIG_RESP_NONE)
+ * and args is NULL.
+ *
+ * The status argument is the status of the request transaction.
+ * If it's anything other than RADIO_TX_STATUS_OK, the request
+ * transaction failed (or response didn't arrive in time) and
+ * the other arguments can be ignored.
+ *
+ * If status is RADIO_TX_STATUS_OK then the resp, error and args
+ * arguments contain the information received in the response.
+ */
+typedef
+void
+(*RadioRequestCompleteFunc)(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* args,
+ gpointer user_data);
+
+typedef
+void
+(*RadioConfigRequestCompleteFunc)(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_CONFIG_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* args,
+ gpointer user_data); /* Since 1.4.6 */
+
+/*
+ * RadioRequestRetryFunc
+ *
+ * If retries are enabled with radio_request_set_retry_func(), then this
+ * callback is invoiked to check whether the request should be retried,
+ * based on the status received from the radio service and the contents
+ * of the reply. If such callback returns TRUE, the request is retried
+ * at some point in the future with a new serial, otherwise it gets
+ * completed right away.
+ *
+ * user_data is the pointer passed to radio_request_new() when the request
+ * was created.
+ */
+typedef
+gboolean
+(*RadioRequestRetryFunc)(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ guint32 resp, /* Was RADIO_RESP before 1.4.6 */
+ RADIO_ERROR error,
+ const GBinderReader* args,
+ void* user_data);
+
+RadioRequest*
+radio_request_new(
+ RadioClient* client,
+ RADIO_REQ code,
+ GBinderWriter* args, /* NULL if serial is the only arg */
+ RadioRequestCompleteFunc complete,
+ GDestroyNotify destroy,
+ void* user_data)
+ G_GNUC_WARN_UNUSED_RESULT;
+
+RadioRequest*
+radio_request_new2(
+ RadioRequestGroup* group,
+ RADIO_REQ code,
+ GBinderWriter* args, /* NULL if serial is the only arg */
+ RadioRequestCompleteFunc complete,
+ GDestroyNotify destroy,
+ void* user_data)
+ G_GNUC_WARN_UNUSED_RESULT;
+
+RadioRequest*
+radio_config_request_new(
+ RadioConfig* config,
+ RADIO_CONFIG_REQ code,
+ GBinderWriter* args, /* NULL if serial is the only arg */
+ RadioConfigRequestCompleteFunc complete,
+ GDestroyNotify destroy,
+ void* user_data) /* Since 1.4.6 */
+ G_GNUC_WARN_UNUSED_RESULT;
+
+RadioRequest*
+radio_request_ref(
+ RadioRequest* req);
+
+void
+radio_request_unref(
+ RadioRequest* req);
+
+void
+radio_request_set_blocking(
+ RadioRequest* req,
+ gboolean blocking);
+
+void
+radio_request_set_timeout(
+ RadioRequest* req,
+ guint milliseconds); /* Zero to use the default timeout */
+
+void
+radio_request_set_retry(
+ RadioRequest* req,
+ guint delay_ms, /* Delay before each retry, in milliseconds */
+ int max_count); /* Negative count to keep retrying indefinitely */
+
+void
+radio_request_set_retry_func(
+ RadioRequest* req,
+ RadioRequestRetryFunc retry);
+
+gboolean
+radio_request_submit(
+ RadioRequest* req);
+
+gboolean
+radio_request_retry(
+ RadioRequest* req);
+
+void
+radio_request_cancel(
+ RadioRequest* req);
+
+void
+radio_request_drop( /* cancel and unref */
+ RadioRequest* req);
+
+void
+radio_request_set_retry_func(
+ RadioRequest* req,
+ RadioRequestRetryFunc retry);
+
+void*
+radio_request_user_data(
+ RadioRequest* req); /* Since 1.4.11 */
+
+G_END_DECLS
+
+#endif /* RADIO_REQUEST_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/include/radio_request_group.h
^
|
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 Jolla Ltd.
+ * Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#ifndef RADIO_REQUEST_GROUP_H
+#define RADIO_REQUEST_GROUP_H
+
+/* This API exists since 1.4.3 */
+
+#include <radio_types.h>
+
+/*
+ * In addition to being just a group of requests and making it easier
+ * to perform bulk operations (i.e. cancel all), RadioRequestGroup can
+ * be given the "blocker" status by its RadioClient and then only requests
+ * belonging to this group will be submitted until the block is released.
+ */
+
+G_BEGIN_DECLS
+
+struct radio_request_group {
+ RadioClient* client;
+};
+
+RadioRequestGroup*
+radio_request_group_new(
+ RadioClient* client)
+ G_GNUC_WARN_UNUSED_RESULT;
+
+RadioRequestGroup*
+radio_request_group_ref(
+ RadioRequestGroup* group);
+
+void
+radio_request_group_unref(
+ RadioRequestGroup* group);
+
+void
+radio_request_group_cancel(
+ RadioRequestGroup* group);
+
+RADIO_BLOCK
+radio_request_group_block_status(
+ RadioRequestGroup* group);
+
+RADIO_BLOCK
+radio_request_group_block(
+ RadioRequestGroup* group);
+
+void
+radio_request_group_unblock(
+ RadioRequestGroup* group);
+
+G_END_DECLS
+
+#endif /* RADIO_REQUEST_GROUP_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Changed |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/include/radio_types.h
^
|
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2018-2021 Jolla Ltd.
- * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
+ * Copyright (C) 2018-2022 Jolla Ltd.
+ * Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2021 Open Mobile Platform LLC.
*
* You may use this file under the terms of the BSD license as follows:
@@ -42,8 +42,35 @@
G_BEGIN_DECLS
+typedef struct radio_client RadioClient;
+typedef struct radio_config RadioConfig;
typedef struct radio_instance RadioInstance;
typedef struct radio_registry RadioRegistry;
+typedef struct radio_request RadioRequest;
+typedef struct radio_request_group RadioRequestGroup;
+
+typedef enum radio_block_status {
+ RADIO_BLOCK_NONE,
+ RADIO_BLOCK_QUEUED,
+ RADIO_BLOCK_ACQUIRED
+} RADIO_BLOCK; /* Since 1.4.3 */
+
+typedef enum radio_interface {
+ RADIO_INTERFACE_NONE = -1, /* Since 1.4.3 */
+ RADIO_INTERFACE_1_0,
+ RADIO_INTERFACE_1_1,
+ RADIO_INTERFACE_1_2,
+ RADIO_INTERFACE_1_3,
+ RADIO_INTERFACE_1_4,
+ RADIO_INTERFACE_1_5, /* Since 1.5.0 */
+ RADIO_INTERFACE_COUNT
+} RADIO_INTERFACE; /* Since 1.2.0 */
+
+typedef enum radio_observer_priority {
+ RADIO_OBSERVER_PRIORITY_LOWEST,
+ RADIO_OBSERVER_PRIORITY_DEFAULT = 2,
+ RADIO_OBSERVER_PRIORITY_HIGHEST = 7
+} RADIO_OBSERVER_PRIORITY; /* Since 1.4.6 */
#define RADIO_IFACE_PREFIX "android.hardware.radio@"
#define RADIO_IFACE "IRadio"
@@ -54,21 +81,25 @@
#define RADIO_IFACE_1_2(x) RADIO_IFACE_PREFIX "1.2::" x
#define RADIO_IFACE_1_3(x) RADIO_IFACE_PREFIX "1.3::" x
#define RADIO_IFACE_1_4(x) RADIO_IFACE_PREFIX "1.4::" x
+#define RADIO_IFACE_1_5(x) RADIO_IFACE_PREFIX "1.5::" x
#define RADIO_1_0 RADIO_IFACE_1_0(RADIO_IFACE)
#define RADIO_1_1 RADIO_IFACE_1_1(RADIO_IFACE)
#define RADIO_1_2 RADIO_IFACE_1_2(RADIO_IFACE)
#define RADIO_1_3 RADIO_IFACE_1_3(RADIO_IFACE)
#define RADIO_1_4 RADIO_IFACE_1_4(RADIO_IFACE)
+#define RADIO_1_5 RADIO_IFACE_1_5(RADIO_IFACE)
#define RADIO_RESPONSE_1_0 RADIO_IFACE_1_0(RADIO_RESPONSE_IFACE)
#define RADIO_RESPONSE_1_1 RADIO_IFACE_1_1(RADIO_RESPONSE_IFACE)
#define RADIO_RESPONSE_1_2 RADIO_IFACE_1_2(RADIO_RESPONSE_IFACE)
#define RADIO_RESPONSE_1_3 RADIO_IFACE_1_3(RADIO_RESPONSE_IFACE)
#define RADIO_RESPONSE_1_4 RADIO_IFACE_1_4(RADIO_RESPONSE_IFACE)
+#define RADIO_RESPONSE_1_5 RADIO_IFACE_1_5(RADIO_RESPONSE_IFACE)
#define RADIO_INDICATION_1_0 RADIO_IFACE_1_0(RADIO_INDICATION_IFACE)
#define RADIO_INDICATION_1_1 RADIO_IFACE_1_1(RADIO_INDICATION_IFACE)
#define RADIO_INDICATION_1_2 RADIO_IFACE_1_2(RADIO_INDICATION_IFACE)
#define RADIO_INDICATION_1_3 RADIO_IFACE_1_3(RADIO_INDICATION_IFACE)
#define RADIO_INDICATION_1_4 RADIO_IFACE_1_4(RADIO_INDICATION_IFACE)
+#define RADIO_INDICATION_1_5 RADIO_IFACE_1_5(RADIO_INDICATION_IFACE)
/* Types defined in types.hal */
@@ -87,6 +118,94 @@
} RADIO_IND_TYPE;
G_STATIC_ASSERT(sizeof(RADIO_IND_TYPE) == 4);
+typedef enum radio_error {
+ RADIO_ERROR_NONE = 0,
+ RADIO_ERROR_RADIO_NOT_AVAILABLE = 1,
+ RADIO_ERROR_GENERIC_FAILURE = 2,
+ RADIO_ERROR_PASSWORD_INCORRECT = 3,
+ RADIO_ERROR_SIM_PIN2 = 4,
+ RADIO_ERROR_SIM_PUK2 = 5,
+ RADIO_ERROR_REQUEST_NOT_SUPPORTED = 6,
+ RADIO_ERROR_CANCELLED = 7,
+ RADIO_ERROR_OP_NOT_ALLOWED_DURING_VOICE_CALL = 8,
+ RADIO_ERROR_OP_NOT_ALLOWED_BEFORE_REG_TO_NW = 9,
+ RADIO_ERROR_SMS_SEND_FAIL_RETRY = 10,
+ RADIO_ERROR_SIM_ABSENT = 11,
+ RADIO_ERROR_SUBSCRIPTION_NOT_AVAILABLE = 12,
+ RADIO_ERROR_MODE_NOT_SUPPORTED = 13,
+ RADIO_ERROR_FDN_CHECK_FAILURE = 14,
+ RADIO_ERROR_ILLEGAL_SIM_OR_ME = 15,
+ RADIO_ERROR_MISSING_RESOURCE = 16,
+ RADIO_ERROR_NO_SUCH_ELEMENT = 17,
+ RADIO_ERROR_DIAL_MODIFIED_TO_USSD = 18,
+ RADIO_ERROR_DIAL_MODIFIED_TO_SS = 19,
+ RADIO_ERROR_DIAL_MODIFIED_TO_DIAL = 20,
+ RADIO_ERROR_USSD_MODIFIED_TO_DIAL = 21,
+ RADIO_ERROR_USSD_MODIFIED_TO_SS = 22,
+ RADIO_ERROR_USSD_MODIFIED_TO_USSD = 23,
+ RADIO_ERROR_SS_MODIFIED_TO_DIAL = 24,
+ RADIO_ERROR_SS_MODIFIED_TO_USSD = 25,
+ RADIO_ERROR_SUBSCRIPTION_NOT_SUPPORTED = 26,
+ RADIO_ERROR_SS_MODIFIED_TO_SS = 27,
+ RADIO_ERROR_LCE_NOT_SUPPORTED = 36,
+ RADIO_ERROR_NO_MEMORY = 37,
+ RADIO_ERROR_INTERNAL_ERR = 38,
+ RADIO_ERROR_SYSTEM_ERR = 39,
+ RADIO_ERROR_MODEM_ERR = 40,
+ RADIO_ERROR_INVALID_STATE = 41,
+ RADIO_ERROR_NO_RESOURCES = 42,
+ RADIO_ERROR_SIM_ERR = 43,
+ RADIO_ERROR_INVALID_ARGUMENTS = 44,
+ RADIO_ERROR_INVALID_SIM_STATE = 45,
+ RADIO_ERROR_INVALID_MODEM_STATE = 46,
+ RADIO_ERROR_INVALID_CALL_ID = 47,
+ RADIO_ERROR_NO_SMS_TO_ACK = 48,
+ RADIO_ERROR_NETWORK_ERR = 49,
+ RADIO_ERROR_REQUEST_RATE_LIMITED = 50,
+ RADIO_ERROR_SIM_BUSY = 51,
+ RADIO_ERROR_SIM_FULL = 52,
+ RADIO_ERROR_NETWORK_REJECT = 53,
+ RADIO_ERROR_OPERATION_NOT_ALLOWED = 54,
+ RADIO_ERROR_EMPTY_RECORD = 55,
+ RADIO_ERROR_INVALID_SMS_FORMAT = 56,
+ RADIO_ERROR_ENCODING_ERR = 57,
+ RADIO_ERROR_INVALID_SMSC_ADDRESS = 58,
+ RADIO_ERROR_NO_SUCH_ENTRY = 59,
+ RADIO_ERROR_NETWORK_NOT_READY = 60,
+ RADIO_ERROR_NOT_PROVISIONED = 61,
+ RADIO_ERROR_NO_SUBSCRIPTION = 62,
+ RADIO_ERROR_NO_NETWORK_FOUND = 63,
+ RADIO_ERROR_DEVICE_IN_USE = 64,
+ RADIO_ERROR_ABORTED = 65,
+ RADIO_ERROR_INVALID_RESPONSE = 66,
+ RADIO_ERROR_OEM_ERROR_1 = 501,
+ RADIO_ERROR_OEM_ERROR_2 = 502,
+ RADIO_ERROR_OEM_ERROR_3 = 503,
+ RADIO_ERROR_OEM_ERROR_4 = 504,
+ RADIO_ERROR_OEM_ERROR_5 = 505,
+ RADIO_ERROR_OEM_ERROR_6 = 506,
+ RADIO_ERROR_OEM_ERROR_7 = 507,
+ RADIO_ERROR_OEM_ERROR_8 = 508,
+ RADIO_ERROR_OEM_ERROR_9 = 509,
+ RADIO_ERROR_OEM_ERROR_10 = 510,
+ RADIO_ERROR_OEM_ERROR_11 = 511,
+ RADIO_ERROR_OEM_ERROR_12 = 512,
+ RADIO_ERROR_OEM_ERROR_13 = 513,
+ RADIO_ERROR_OEM_ERROR_14 = 514,
+ RADIO_ERROR_OEM_ERROR_15 = 515,
+ RADIO_ERROR_OEM_ERROR_16 = 516,
+ RADIO_ERROR_OEM_ERROR_17 = 517,
+ RADIO_ERROR_OEM_ERROR_18 = 518,
+ RADIO_ERROR_OEM_ERROR_19 = 519,
+ RADIO_ERROR_OEM_ERROR_20 = 520,
+ RADIO_ERROR_OEM_ERROR_21 = 521,
+ RADIO_ERROR_OEM_ERROR_22 = 522,
+ RADIO_ERROR_OEM_ERROR_23 = 523,
+ RADIO_ERROR_OEM_ERROR_24 = 524,
+ RADIO_ERROR_OEM_ERROR_25 = 525
+} RADIO_ERROR; /* Since 1.4.3 */
+G_STATIC_ASSERT(sizeof(RADIO_ERROR) == 4);
+
typedef enum radio_state {
RADIO_STATE_OFF = 0,
RADIO_STATE_UNAVAILABLE = 1,
@@ -108,6 +227,12 @@
} RADIO_REG_STATE;
G_STATIC_ASSERT(sizeof(RADIO_REG_STATE) == 4);
+typedef enum radio_reg_access_technology_specific_info_type {
+ RADIO_REG_ACCESS_TECHNOLOGY_SPECIFIC_INFO_NONE = 0,
+ RADIO_REG_ACCESS_TECHNOLOGY_SPECIFIC_INFO_CDMA = 1,
+ RADIO_REG_ACCESS_TECHNOLOGY_SPECIFIC_INFO_EUTRAN = 2
+} RADIO_REG_ACCESS_TECHNOLOGY_SPECIFIC_INFO_TYPE; /* Since 1.5.0 */
+
typedef enum radio_ind_filter {
RADIO_IND_FILTER_NONE = 0,
RADIO_IND_FILTER_SIGNAL_STRENGTH = 0x01,
@@ -116,7 +241,11 @@
RADIO_IND_FILTER_ALL =
RADIO_IND_FILTER_SIGNAL_STRENGTH |
RADIO_IND_FILTER_FULL_NETWORK_STATE |
- RADIO_IND_FILTER_DATA_CALL_DORMANCY
+ RADIO_IND_FILTER_DATA_CALL_DORMANCY,
+ /* Since 1.4.4 (those appeared in IRadio@1.2) */
+ RADIO_IND_FILTER_LINK_CAPACITY_ESTIMATE = 0x08,
+ RADIO_IND_FILTER_PHYSICAL_CHANNEL_CONFIG = 0x10,
+ RADIO_IND_FILTER_ALL_1_2 = ~0
} RADIO_IND_FILTER;
G_STATIC_ASSERT(sizeof(RADIO_IND_FILTER) == 4);
@@ -157,6 +286,51 @@
RADIO_CELL_INFO_1_4_NR
} RADIO_CELL_INFO_TYPE_1_4; /* Since 1.4.1 */
+/* Cast guint8 RadioCellInfo_1_5.cellInfoType to this. */
+typedef enum radio_cell_info_type_1_5 {
+ RADIO_CELL_INFO_1_5_GSM = 0,
+ RADIO_CELL_INFO_1_5_WCDMA,
+ RADIO_CELL_INFO_1_5_TD_SCDMA,
+ RADIO_CELL_INFO_1_5_LTE,
+ RADIO_CELL_INFO_1_5_NR,
+ RADIO_CELL_INFO_1_5_CDMA
+} RADIO_CELL_INFO_TYPE_1_5; /* Since 1.5.0 */
+
+/* Cast guint8 RadioCellIdentity_1_5.cellIdentityType to this. */
+typedef enum radio_cell_identity_type_1_5 {
+ RADIO_CELL_IDENTITY_1_5_GSM = 0,
+ RADIO_CELL_IDENTITY_1_5_WCDMA,
+ RADIO_CELL_IDENTITY_1_5_TD_SCDMA,
+ RADIO_CELL_IDENTITY_1_5_CDMA,
+ RADIO_CELL_IDENTITY_1_5_LTE,
+ RADIO_CELL_IDENTITY_1_5_NR
+} RADIO_CELL_IDENTITY_TYPE_1_5; /* Since 1.5.0 */
+
+/* Valid values of RadioNetworkScanRequest_1_5::type */
+typedef enum radio_network_scan_specifier_1_5_type {
+ RADIO_NETWORK_SCAN_SPECIFIER_1_5_GERAN = 0,
+ RADIO_NETWORK_SCAN_SPECIFIER_1_5_UTRAN,
+ RADIO_NETWORK_SCAN_SPECIFIER_1_5_EUTRAN,
+ RADIO_NETWORK_SCAN_SPECIFIER_1_5_NGRAN
+} RADIO_NETWORK_SCAN_SPECIFIER_1_5_TYPE; /* Since 1.5.2 */
+
+typedef enum radio_frequency_info_type {
+ RADIO_FREQUENCY_INFO_TYPE_RANGE,
+ RADIO_FREQUENCY_INFO_TYPE_CHANNEL_NUMBER,
+} RADIO_FREQUENCY_INFO_TYPE; /* Since 1.5.4 */;
+
+typedef enum radio_frequency_range {
+ /* Indicates the frequency range is below 1GHz. */
+ RADIO_FREQUENCY_RANGE_LOW = 1,
+ /* Indicates the frequency range is between 1GHz and 3GHz. */
+ RADIO_FREQUENCY_RANGE_MID,
+ /* Indicates the frequency range is between 3GHz and 6GHz. */
+ RADIO_FREQUENCY_RANGE_HIGH,
+ /* Indicates the frequency range is above 6GHz (millimeter wave frequency). */
+ RADIO_FREQUENCY_RANGE_MMWAVE,
+} RADIO_FREQUENCY_RANGE; /* Since 1.5.4 */;
+G_STATIC_ASSERT(sizeof(RADIO_FREQUENCY_RANGE) == 4);
+
typedef enum radio_tech {
RADIO_TECH_UNKNOWN = 0,
RADIO_TECH_GPRS,
@@ -177,11 +351,13 @@
RADIO_TECH_GSM,
RADIO_TECH_TD_SCDMA,
RADIO_TECH_IWLAN,
- RADIO_TECH_LTE_CA
+ RADIO_TECH_LTE_CA,
+ RADIO_TECH_NR /* Since 1.5.4 */
} RADIO_TECH;
G_STATIC_ASSERT(sizeof(RADIO_TECH) == 4);
typedef enum radio_access_family {
+ RAF_NONE = 0, /* Since 1.4.3 */
RAF_UNKNOWN = (1 << RADIO_TECH_UNKNOWN),
RAF_GPRS = (1 << RADIO_TECH_GPRS),
RAF_EDGE = (1 << RADIO_TECH_EDGE),
@@ -201,7 +377,8 @@
RAF_GSM = (1 << RADIO_TECH_GSM),
RAF_TD_SCDMA = (1 << RADIO_TECH_TD_SCDMA),
RAF_IWLAN = (1 << RADIO_TECH_IWLAN),
- RAF_LTE_CA = (1 << RADIO_TECH_LTE_CA)
+ RAF_LTE_CA = (1 << RADIO_TECH_LTE_CA),
+ RAF_NR = (1 << RADIO_TECH_NR) /* Since 1.5.4 */
} RADIO_ACCESS_FAMILY;
G_STATIC_ASSERT(sizeof(RADIO_ACCESS_FAMILY) == 4);
@@ -226,10 +403,12 @@
RADIO_APN_TYPE_IA = 1 << 8,
RADIO_APN_TYPE_EMERGENCY = 1 << 9,
RADIO_APN_TYPE_MCX = 1 << 10, /* Since 1.2.5 */
+ RADIO_APN_TYPE_XCAP = 1 << 11, /* Since 1.5.0 */
RADIO_APN_TYPE_ALL = RADIO_APN_TYPE_DEFAULT | RADIO_APN_TYPE_MMS |
RADIO_APN_TYPE_SUPL | RADIO_APN_TYPE_DUN | RADIO_APN_TYPE_HIPRI |
RADIO_APN_TYPE_FOTA | RADIO_APN_TYPE_IMS | RADIO_APN_TYPE_CBS |
- RADIO_APN_TYPE_IA | RADIO_APN_TYPE_EMERGENCY | RADIO_APN_TYPE_MCX
+ RADIO_APN_TYPE_IA | RADIO_APN_TYPE_EMERGENCY | RADIO_APN_TYPE_MCX |
+ RADIO_APN_TYPE_XCAP
} RADIO_APN_TYPES;
G_STATIC_ASSERT(sizeof(RADIO_APN_TYPES) == 4);
@@ -341,16 +520,29 @@
} RADIO_DATA_REQUEST_REASON; /* Since 1.2.0 */
G_STATIC_ASSERT(sizeof(RADIO_DATA_REQUEST_REASON) == 4);
+/* This is AccessNetwork from types.hal */
typedef enum radio_access_network {
RADIO_ACCESS_NETWORK_UNKNOWN,
RADIO_ACCESS_NETWORK_GERAN,
RADIO_ACCESS_NETWORK_UTRAN,
RADIO_ACCESS_NETWORK_EUTRAN,
RADIO_ACCESS_NETWORK_CDMA2000,
- RADIO_ACCESS_NETWORK_IWLAN
+ RADIO_ACCESS_NETWORK_IWLAN,
+ RADIO_ACCESS_NETWORK_NGRAN /* Since 1.5.0 */
} RADIO_ACCESS_NETWORK; /* Since 1.2.0 */
G_STATIC_ASSERT(sizeof(RADIO_ACCESS_NETWORK) == 4);
+/* And this is RadioAccessNetworks (easy to confuse with AccessNetwork) */
+typedef enum radio_access_networks {
+ RADIO_ACCESS_NETWORKS_UNKNOWN,
+ RADIO_ACCESS_NETWORKS_GERAN,
+ RADIO_ACCESS_NETWORKS_UTRAN,
+ RADIO_ACCESS_NETWORKS_EUTRAN,
+ RADIO_ACCESS_NETWORKS_NGRAN,
+ RADIO_ACCESS_NETWORKS_CDMA2000
+} RADIO_ACCESS_NETWORKS; /* Since 1.5.3 */
+G_STATIC_ASSERT(sizeof(RADIO_ACCESS_NETWORKS) == 4);
+
typedef enum radio_data_profile_type {
RADIO_DATA_PROFILE_COMMON,
RADIO_DATA_PROFILE_3GPP,
@@ -358,6 +550,12 @@
} RADIO_DATA_PROFILE_TYPE; /* Since 1.2.5 */
G_STATIC_ASSERT(sizeof(RADIO_DATA_PROFILE_TYPE) == 4);
+typedef enum radio_tech_family {
+ RADIO_TECH_FAMILY_3GPP,
+ RADIO_TECH_FAMILY_3GPP2
+} RADIO_TECH_FAMILY; /* Since 1.4.9 */
+G_STATIC_ASSERT(sizeof(RADIO_TECH_FAMILY) == 4);
+
typedef enum radio_pdp_protocol_type {
RADIO_PDP_PROTOCOL_UNKNOWN = -1,
RADIO_PDP_PROTOCOL_IP,
@@ -402,10 +600,719 @@
} RADIO_SCAN_STATUS; /* Since 1.2.5 */
G_STATIC_ASSERT(sizeof(RADIO_SCAN_STATUS) == 4);
+typedef enum radio_scan_type {
+ RADIO_SCAN_ONE_SHOT,
+ RADIO_SCAN_PERIODIC
+} RADIO_SCAN_TYPE; /* Since 1.5.2 */
+G_STATIC_ASSERT(sizeof(RADIO_SCAN_TYPE) == 4);
+
+typedef enum radio_uicc_sub_act {
+ RADIO_UICC_SUB_DEACTIVATE,
+ RADIO_UICC_SUB_ACTIVATE
+} RADIO_UICC_SUB_ACT; /* Since 1.4.3 */
+G_STATIC_ASSERT(sizeof(RADIO_UICC_SUB_ACT) == 4);
+
+typedef enum radio_service_class {
+ RADIO_SERVICE_CLASS_NONE = 0,
+ RADIO_SERVICE_CLASS_VOICE = 1 << 0,
+ RADIO_SERVICE_CLASS_DATA = 1 << 1,
+ RADIO_SERVICE_CLASS_FAX = 1 << 2,
+ RADIO_SERVICE_CLASS_SMS = 1 << 3,
+ RADIO_SERVICE_CLASS_DATA_SYNC = 1 << 4,
+ RADIO_SERVICE_CLASS_DATA_ASYNC = 1 << 5,
+ RADIO_SERVICE_CLASS_PACKET = 1 << 6,
+ RADIO_SERVICE_CLASS_PAD = 1 << 7
+} RADIO_SERVICE_CLASS; /* Since 1.4.3 */
+G_STATIC_ASSERT(sizeof(RADIO_SERVICE_CLASS) == 4);
+
+typedef enum radio_call_forward {
+ RADIO_CALL_FORWARD_DISABLE,
+ RADIO_CALL_FORWARD_ENABLE,
+ RADIO_CALL_FORWARD_INTERROGATE,
+ RADIO_CALL_FORWARD_REGISTRATION,
+ RADIO_CALL_FORWARD_ERASURE
+} RADIO_CALL_FORWARD; /* Since 1.4.3 */
+G_STATIC_ASSERT(sizeof(RADIO_CALL_FORWARD) == 4);
+
+typedef enum radio_data_call_active_status {
+ RADIO_DATA_CALL_INACTIVE = 0,
+ RADIO_DATA_CALL_DORMANT = 1,
+ RADIO_DATA_CALL_ACTIVE = 2
+} RADIO_DATA_CALL_ACTIVE_STATUS; /* Since 1.4.3 */
+G_STATIC_ASSERT(sizeof(RADIO_DATA_CALL_ACTIVE_STATUS) == 4);
+
+typedef enum radio_restricted_state {
+ RADIO_RESTRICTED_STATE_NONE = 0x00,
+ RADIO_RESTRICTED_STATE_CS_EMERGENCY = 0x01,
+ RADIO_RESTRICTED_STATE_CS_NORMAL = 0x02,
+ RADIO_RESTRICTED_STATE_CS_ALL = 0x04,
+ RADIO_RESTRICTED_STATE_PS_ALL = 0x10
+} RADIO_RESTRICTED_STATE; /* Since 1.4.3 */
+G_STATIC_ASSERT(sizeof(RADIO_RESTRICTED_STATE) == 4);
+
+typedef enum radio_pref_net_type {
+ RADIO_PREF_NET_INVALID = -1,
+ RADIO_PREF_NET_GSM_WCDMA,
+ RADIO_PREF_NET_GSM_ONLY,
+ RADIO_PREF_NET_WCDMA,
+ RADIO_PREF_NET_GSM_WCDMA_AUTO,
+ RADIO_PREF_NET_CDMA_EVDO_AUTO,
+ RADIO_PREF_NET_CDMA_ONLY,
+ RADIO_PREF_NET_EVDO_ONLY,
+ RADIO_PREF_NET_GSM_WCDMA_CDMA_EVDO_AUTO,
+ RADIO_PREF_NET_LTE_CDMA_EVDO,
+ RADIO_PREF_NET_LTE_GSM_WCDMA,
+ RADIO_PREF_NET_LTE_CMDA_EVDO_GSM_WCDMA,
+ RADIO_PREF_NET_LTE_ONLY,
+ RADIO_PREF_NET_LTE_WCDMA,
+ RADIO_PREF_NET_TD_SCDMA_ONLY,
+ RADIO_PREF_NET_TD_SCDMA_WCDMA,
+ RADIO_PREF_NET_TD_SCDMA_LTE,
+ RADIO_PREF_NET_TD_SCDMA_GSM,
+ RADIO_PREF_NET_TD_SCDMA_GSM_LTE,
+ RADIO_PREF_NET_TD_SCDMA_GSM_WCDMA,
+ RADIO_PREF_NET_TD_SCDMA_WCDMA_LTE,
+ RADIO_PREF_NET_TD_SCDMA_GSM_WCDMA_LTE,
+ RADIO_PREF_NET_TD_SCDMA_GSM_WCDMA_CDMA_EVDO_AUTO,
+ RADIO_PREF_NET_TD_SCDMA_LTE_CDMA_EVDO_GSM_WCDMA
+} RADIO_PREF_NET_TYPE; /* Since 1.4.3 */
+G_STATIC_ASSERT(sizeof(RADIO_PREF_NET_TYPE) == 4);
+
+typedef enum radio_ussd_type {
+ RADIO_USSD_NOTIFY,
+ RADIO_USSD_REQUEST,
+ RADIO_USSD_NW_RELEASE,
+ RADIO_USSD_LOCAL_CLIENT,
+ RADIO_USSD_NOT_SUPPORTED,
+ RADIO_USSD_NW_TIMEOUT
+} RADIO_USSD_TYPE; /* Since 1.4.3 */
+G_STATIC_ASSERT(sizeof(RADIO_USSD_TYPE) == 4);
+
+typedef enum radio_sms_ack_fail_cause {
+ RADIO_SMS_ACK_FAIL_NONE = 0,
+ RADIO_SMS_ACK_FAIL_MEMORY_CAPACITY_EXCEEDED = 0xD3,
+ RADIO_SMS_ACK_FAIL_UNSPECIFIED_ERROR = 0XFF
+} RADIO_SMS_ACK_FAIL_CAUSE; /* Since 1.4.3 */
+G_STATIC_ASSERT(sizeof(RADIO_SMS_ACK_FAIL_CAUSE) == 4);
+
+typedef enum radio_clir {
+ RADIO_CLIR_DEFAULT,
+ RADIO_CLIR_INVOCATION,
+ RADIO_CLIR_SUPPRESSION
+} RADIO_CLIR; /* Since 1.4.3 */
+G_STATIC_ASSERT(sizeof(RADIO_CLIR) == 4);
+
+typedef enum radio_geran_band {
+ RADIO_GERAN_BAND_T380 = 1,
+ RADIO_GERAN_BAND_T410 = 2,
+ RADIO_GERAN_BAND_450 = 3,
+ RADIO_GERAN_BAND_480 = 4,
+ RADIO_GERAN_BAND_710 = 5,
+ RADIO_GERAN_BAND_750 = 6,
+ RADIO_GERAN_BAND_T810 = 7,
+ RADIO_GERAN_BAND_850 = 8,
+ RADIO_GERAN_BAND_P900 = 9,
+ RADIO_GERAN_BAND_E900 = 10,
+ RADIO_GERAN_BAND_R900 = 11,
+ RADIO_GERAN_BAND_DCS1800 = 12,
+ RADIO_GERAN_BAND_PCS1900 = 13,
+ RADIO_GERAN_BAND_ER900 = 14
+} RADIO_GERAN_BAND; /* Since 1.5.2 */
+G_STATIC_ASSERT(sizeof(RADIO_GERAN_BAND) == 4);
+
+typedef enum radio_utran_band {
+ RADIO_UTRAN_BAND_1 = 1,
+ RADIO_UTRAN_BAND_2 = 2,
+ RADIO_UTRAN_BAND_3 = 3,
+ RADIO_UTRAN_BAND_4 = 4,
+ RADIO_UTRAN_BAND_5 = 5,
+ RADIO_UTRAN_BAND_6 = 6,
+ RADIO_UTRAN_BAND_7 = 7,
+ RADIO_UTRAN_BAND_8 = 8,
+ RADIO_UTRAN_BAND_9 = 9,
+ RADIO_UTRAN_BAND_10 = 10,
+ RADIO_UTRAN_BAND_11 = 11,
+ RADIO_UTRAN_BAND_12 = 12,
+ RADIO_UTRAN_BAND_13 = 13,
+ RADIO_UTRAN_BAND_14 = 14,
+ RADIO_UTRAN_BAND_19 = 19,
+ RADIO_UTRAN_BAND_20 = 20,
+ RADIO_UTRAN_BAND_21 = 21,
+ RADIO_UTRAN_BAND_22 = 22,
+ RADIO_UTRAN_BAND_25 = 25,
+ RADIO_UTRAN_BAND_26 = 26,
+ RADIO_UTRAN_BAND_A = 101, /* Since IRadio 1.5 */
+ RADIO_UTRAN_BAND_B = 102, /* Since IRadio 1.5 */
+ RADIO_UTRAN_BAND_C = 103, /* Since IRadio 1.5 */
+ RADIO_UTRAN_BAND_D = 104, /* Since IRadio 1.5 */
+ RADIO_UTRAN_BAND_E = 105, /* Since IRadio 1.5 */
+ RADIO_UTRAN_BAND_F = 106 /* Since IRadio 1.5 */
+} RADIO_UTRAN_BAND; /* Since 1.5.2 */
+G_STATIC_ASSERT(sizeof(RADIO_UTRAN_BAND) == 4);
+
+typedef enum radio_eutran_band {
+ RADIO_EUTRAN_BAND_1 = 1,
+ RADIO_EUTRAN_BAND_2 = 2,
+ RADIO_EUTRAN_BAND_3 = 3,
+ RADIO_EUTRAN_BAND_4 = 4,
+ RADIO_EUTRAN_BAND_5 = 5,
+ RADIO_EUTRAN_BAND_6 = 6,
+ RADIO_EUTRAN_BAND_7 = 7,
+ RADIO_EUTRAN_BAND_8 = 8,
+ RADIO_EUTRAN_BAND_9 = 9,
+ RADIO_EUTRAN_BAND_10 = 10,
+ RADIO_EUTRAN_BAND_11 = 11,
+ RADIO_EUTRAN_BAND_12 = 12,
+ RADIO_EUTRAN_BAND_13 = 13,
+ RADIO_EUTRAN_BAND_14 = 14,
+ RADIO_EUTRAN_BAND_17 = 17,
+ RADIO_EUTRAN_BAND_18 = 18,
+ RADIO_EUTRAN_BAND_19 = 19,
+ RADIO_EUTRAN_BAND_20 = 20,
+ RADIO_EUTRAN_BAND_21 = 21,
+ RADIO_EUTRAN_BAND_22 = 22,
+ RADIO_EUTRAN_BAND_23 = 23,
+ RADIO_EUTRAN_BAND_24 = 24,
+ RADIO_EUTRAN_BAND_25 = 25,
+ RADIO_EUTRAN_BAND_26 = 26,
+ RADIO_EUTRAN_BAND_27 = 27,
+ RADIO_EUTRAN_BAND_28 = 28,
+ RADIO_EUTRAN_BAND_30 = 30,
+ RADIO_EUTRAN_BAND_31 = 31,
+ RADIO_EUTRAN_BAND_33 = 33,
+ RADIO_EUTRAN_BAND_34 = 34,
+ RADIO_EUTRAN_BAND_35 = 35,
+ RADIO_EUTRAN_BAND_36 = 36,
+ RADIO_EUTRAN_BAND_37 = 37,
+ RADIO_EUTRAN_BAND_38 = 38,
+ RADIO_EUTRAN_BAND_39 = 39,
+ RADIO_EUTRAN_BAND_40 = 40,
+ RADIO_EUTRAN_BAND_41 = 41,
+ RADIO_EUTRAN_BAND_42 = 42,
+ RADIO_EUTRAN_BAND_43 = 43,
+ RADIO_EUTRAN_BAND_44 = 44,
+ RADIO_EUTRAN_BAND_45 = 45,
+ RADIO_EUTRAN_BAND_46 = 46,
+ RADIO_EUTRAN_BAND_47 = 47,
+ RADIO_EUTRAN_BAND_48 = 48,
+ RADIO_EUTRAN_BAND_49 = 49, /* Since IRadio 1.5 */
+ RADIO_EUTRAN_BAND_50 = 50, /* Since IRadio 1.5 */
+ RADIO_EUTRAN_BAND_51 = 51, /* Since IRadio 1.5 */
+ RADIO_EUTRAN_BAND_52 = 52, /* Since IRadio 1.5 */
+ RADIO_EUTRAN_BAND_53 = 53, /* Since IRadio 1.5 */
+ RADIO_EUTRAN_BAND_65 = 65,
+ RADIO_EUTRAN_BAND_66 = 66,
+ RADIO_EUTRAN_BAND_68 = 68,
+ RADIO_EUTRAN_BAND_70 = 70,
+ RADIO_EUTRAN_BAND_71 = 71, /* Since IRadio 1.5 */
+ RADIO_EUTRAN_BAND_72 = 72, /* Since IRadio 1.5 */
+ RADIO_EUTRAN_BAND_73 = 73, /* Since IRadio 1.5 */
+ RADIO_EUTRAN_BAND_74 = 74, /* Since IRadio 1.5 */
+ RADIO_EUTRAN_BAND_85 = 85, /* Since IRadio 1.5 */
+ RADIO_EUTRAN_BAND_87 = 87, /* Since IRadio 1.5 */
+ RADIO_EUTRAN_BAND_88 = 88 /* Since IRadio 1.5 */
+} RADIO_EUTRAN_BAND; /* Since 1.5.2 */
+G_STATIC_ASSERT(sizeof(RADIO_EUTRAN_BAND) == 4);
+
+typedef enum radio_ngran_band {
+ RADIO_NGRAN_BAND_1 = 1,
+ RADIO_NGRAN_BAND_2 = 2,
+ RADIO_NGRAN_BAND_3 = 3,
+ RADIO_NGRAN_BAND_5 = 5,
+ RADIO_NGRAN_BAND_7 = 7,
+ RADIO_NGRAN_BAND_8 = 8,
+ RADIO_NGRAN_BAND_12 = 12,
+ RADIO_NGRAN_BAND_14 = 14,
+ RADIO_NGRAN_BAND_18 = 18,
+ RADIO_NGRAN_BAND_20 = 20,
+ RADIO_NGRAN_BAND_25 = 25,
+ RADIO_NGRAN_BAND_28 = 28,
+ RADIO_NGRAN_BAND_29 = 29,
+ RADIO_NGRAN_BAND_30 = 30,
+ RADIO_NGRAN_BAND_34 = 34,
+ RADIO_NGRAN_BAND_38 = 38,
+ RADIO_NGRAN_BAND_39 = 39,
+ RADIO_NGRAN_BAND_40 = 40,
+ RADIO_NGRAN_BAND_41 = 41,
+ RADIO_NGRAN_BAND_48 = 48,
+ RADIO_NGRAN_BAND_50 = 50,
+ RADIO_NGRAN_BAND_51 = 51,
+ RADIO_NGRAN_BAND_65 = 65,
+ RADIO_NGRAN_BAND_66 = 66,
+ RADIO_NGRAN_BAND_70 = 70,
+ RADIO_NGRAN_BAND_71 = 71,
+ RADIO_NGRAN_BAND_74 = 74,
+ RADIO_NGRAN_BAND_75 = 75,
+ RADIO_NGRAN_BAND_76 = 76,
+ RADIO_NGRAN_BAND_77 = 77,
+ RADIO_NGRAN_BAND_78 = 78,
+ RADIO_NGRAN_BAND_79 = 79,
+ RADIO_NGRAN_BAND_80 = 80,
+ RADIO_NGRAN_BAND_81 = 81,
+ RADIO_NGRAN_BAND_82 = 82,
+ RADIO_NGRAN_BAND_83 = 83,
+ RADIO_NGRAN_BAND_84 = 84,
+ RADIO_NGRAN_BAND_86 = 86,
+ RADIO_NGRAN_BAND_89 = 89,
+ RADIO_NGRAN_BAND_90 = 90,
+ RADIO_NGRAN_BAND_91 = 91,
+ RADIO_NGRAN_BAND_92 = 92,
+ RADIO_NGRAN_BAND_93 = 93,
+ RADIO_NGRAN_BAND_94 = 94,
+ RADIO_NGRAN_BAND_95 = 95,
+ RADIO_NGRAN_BAND_257 = 257,
+ RADIO_NGRAN_BAND_258 = 258,
+ RADIO_NGRAN_BAND_260 = 260,
+ RADIO_NGRAN_BAND_261 = 261
+} RADIO_NGRAN_BAND; /* Since 1.5.2 */
+G_STATIC_ASSERT(sizeof(RADIO_NGRAN_BAND) == 4);
+
+typedef enum radio_last_call_fail_cause {
+ RADIO_LAST_CALL_FAIL_NONE = 0,
+ RADIO_LAST_CALL_FAIL_UNOBTAINABLE_NUMBER = 1,
+ RADIO_LAST_CALL_FAIL_NO_ROUTE_TO_DESTINATION = 3,
+ RADIO_LAST_CALL_FAIL_CHANNEL_UNACCEPTABLE = 6,
+ RADIO_LAST_CALL_FAIL_OPERATOR_DETERMINED_BARRING = 8,
+ RADIO_LAST_CALL_FAIL_NORMAL = 16,
+ RADIO_LAST_CALL_FAIL_BUSY = 17,
+ RADIO_LAST_CALL_FAIL_NO_USER_RESPONDING = 18,
+ RADIO_LAST_CALL_FAIL_NO_ANSWER_FROM_USER = 19,
+ RADIO_LAST_CALL_FAIL_CALL_REJECTED = 21,
+ RADIO_LAST_CALL_FAIL_NUMBER_CHANGED = 22,
+ RADIO_LAST_CALL_FAIL_PREEMPTION = 25,
+ RADIO_LAST_CALL_FAIL_DESTINATION_OUT_OF_ORDER = 27,
+ RADIO_LAST_CALL_FAIL_INVALID_NUMBER_FORMAT = 28,
+ RADIO_LAST_CALL_FAIL_FACILITY_REJECTED = 29,
+ RADIO_LAST_CALL_FAIL_RESP_TO_STATUS_ENQUIRY = 30,
+ RADIO_LAST_CALL_FAIL_NORMAL_UNSPECIFIED = 31,
+ RADIO_LAST_CALL_FAIL_CONGESTION = 34,
+ RADIO_LAST_CALL_FAIL_NETWORK_OUT_OF_ORDER = 38,
+ RADIO_LAST_CALL_FAIL_TEMPORARY_FAILURE = 41,
+ RADIO_LAST_CALL_FAIL_SWITCHING_EQUIPMENT_CONGESTION = 42,
+ RADIO_LAST_CALL_FAIL_ACCESS_INFORMATION_DISCARDED = 43,
+ RADIO_LAST_CALL_FAIL_REQUESTED_CIRCUIT_OR_CHANNEL_NOT_AVAILABLE = 44,
+ RADIO_LAST_CALL_FAIL_RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 47,
+ RADIO_LAST_CALL_FAIL_QOS_UNAVAILABLE = 49,
+ RADIO_LAST_CALL_FAIL_REQUESTED_FACILITY_NOT_SUBSCRIBED = 50,
+ RADIO_LAST_CALL_FAIL_INCOMING_CALLS_BARRED_WITHIN_CUG = 55,
+ RADIO_LAST_CALL_FAIL_BEARER_CAPABILITY_NOT_AUTHORIZED = 57,
+ RADIO_LAST_CALL_FAIL_BEARER_CAPABILITY_UNAVAILABLE = 58,
+ RADIO_LAST_CALL_FAIL_SERVICE_OPTION_NOT_AVAILABLE = 63,
+ RADIO_LAST_CALL_FAIL_BEARER_SERVICE_NOT_IMPLEMENTED = 65,
+ RADIO_LAST_CALL_FAIL_ACM_LIMIT_EXCEEDED = 68,
+ RADIO_LAST_CALL_FAIL_REQUESTED_FACILITY_NOT_IMPLEMENTED = 69,
+ RADIO_LAST_CALL_FAIL_ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 70,
+ RADIO_LAST_CALL_FAIL_SERVICE_OR_OPTION_NOT_IMPLEMENTED = 79,
+ RADIO_LAST_CALL_FAIL_INVALID_TRANSACTION_IDENTIFIER = 81,
+ RADIO_LAST_CALL_FAIL_USER_NOT_MEMBER_OF_CUG = 87,
+ RADIO_LAST_CALL_FAIL_INCOMPATIBLE_DESTINATION = 88,
+ RADIO_LAST_CALL_FAIL_INVALID_TRANSIT_NW_SELECTION = 91,
+ RADIO_LAST_CALL_FAIL_SEMANTICALLY_INCORRECT_MESSAGE = 95,
+ RADIO_LAST_CALL_FAIL_INVALID_MANDATORY_INFORMATION = 96,
+ RADIO_LAST_CALL_FAIL_MESSAGE_TYPE_NON_IMPLEMENTED = 97,
+ RADIO_LAST_CALL_FAIL_MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 98,
+ RADIO_LAST_CALL_FAIL_INFORMATION_ELEMENT_NON_EXISTENT = 99,
+ RADIO_LAST_CALL_FAIL_CONDITIONAL_IE_ERROR = 100,
+ RADIO_LAST_CALL_FAIL_MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101,
+ RADIO_LAST_CALL_FAIL_RECOVERY_ON_TIMER_EXPIRED = 102,
+ RADIO_LAST_CALL_FAIL_PROTOCOL_ERROR_UNSPECIFIED = 111,
+ RADIO_LAST_CALL_FAIL_INTERWORKING_UNSPECIFIED = 127,
+ RADIO_LAST_CALL_FAIL_CALL_BARRED = 240,
+ RADIO_LAST_CALL_FAIL_FDN_BLOCKED = 241,
+ RADIO_LAST_CALL_FAIL_IMSI_UNKNOWN_IN_VLR = 242,
+ RADIO_LAST_CALL_FAIL_IMEI_NOT_ACCEPTED = 243,
+ RADIO_LAST_CALL_FAIL_DIAL_MODIFIED_TO_USSD = 244,
+ RADIO_LAST_CALL_FAIL_DIAL_MODIFIED_TO_SS = 245,
+ RADIO_LAST_CALL_FAIL_DIAL_MODIFIED_TO_DIAL = 246,
+ RADIO_LAST_CALL_FAIL_RADIO_OFF = 247,
+ RADIO_LAST_CALL_FAIL_OUT_OF_SERVICE = 248,
+ RADIO_LAST_CALL_FAIL_NO_VALID_SIM = 249,
+ RADIO_LAST_CALL_FAIL_RADIO_INTERNAL_ERROR = 250,
+ RADIO_LAST_CALL_FAIL_NETWORK_RESP_TIMEOUT = 251,
+ RADIO_LAST_CALL_FAIL_NETWORK_REJECT = 252,
+ RADIO_LAST_CALL_FAIL_RADIO_ACCESS_FAILURE = 253,
+ RADIO_LAST_CALL_FAIL_RADIO_LINK_FAILURE = 254,
+ RADIO_LAST_CALL_FAIL_RADIO_LINK_LOST = 255,
+ RADIO_LAST_CALL_FAIL_RADIO_UPLINK_FAILURE = 256,
+ RADIO_LAST_CALL_FAIL_RADIO_SETUP_FAILURE = 257,
+ RADIO_LAST_CALL_FAIL_RADIO_RELEASE_NORMAL = 258,
+ RADIO_LAST_CALL_FAIL_RADIO_RELEASE_ABNORMAL = 259,
+ RADIO_LAST_CALL_FAIL_ACCESS_CLASS_BLOCKED = 260,
+ RADIO_LAST_CALL_FAIL_NETWORK_DETACH = 261,
+ RADIO_LAST_CALL_FAIL_CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000,
+ RADIO_LAST_CALL_FAIL_CDMA_DROP = 1001,
+ RADIO_LAST_CALL_FAIL_CDMA_INTERCEPT = 1002,
+ RADIO_LAST_CALL_FAIL_CDMA_REORDER = 1003,
+ RADIO_LAST_CALL_FAIL_CDMA_SO_REJECT = 1004,
+ RADIO_LAST_CALL_FAIL_CDMA_RETRY_ORDER = 1005,
+ RADIO_LAST_CALL_FAIL_CDMA_ACCESS_FAILURE = 1006,
+ RADIO_LAST_CALL_FAIL_CDMA_PREEMPTED = 1007,
+ RADIO_LAST_CALL_FAIL_CDMA_NOT_EMERGENCY = 1008,
+ RADIO_LAST_CALL_FAIL_CDMA_ACCESS_BLOCKED = 1009,
+ RADIO_LAST_CALL_FAIL_OEM_CAUSE_1 = 0xf001,
+ RADIO_LAST_CALL_FAIL_OEM_CAUSE_2 = 0xf002,
+ RADIO_LAST_CALL_FAIL_OEM_CAUSE_3 = 0xf003,
+ RADIO_LAST_CALL_FAIL_OEM_CAUSE_4 = 0xf004,
+ RADIO_LAST_CALL_FAIL_OEM_CAUSE_5 = 0xf005,
+ RADIO_LAST_CALL_FAIL_OEM_CAUSE_6 = 0xf006,
+ RADIO_LAST_CALL_FAIL_OEM_CAUSE_7 = 0xf007,
+ RADIO_LAST_CALL_FAIL_OEM_CAUSE_8 = 0xf008,
+ RADIO_LAST_CALL_FAIL_OEM_CAUSE_9 = 0xf009,
+ RADIO_LAST_CALL_FAIL_OEM_CAUSE_10 = 0xf00a,
+ RADIO_LAST_CALL_FAIL_OEM_CAUSE_11 = 0xf00b,
+ RADIO_LAST_CALL_FAIL_OEM_CAUSE_12 = 0xf00c,
+ RADIO_LAST_CALL_FAIL_OEM_CAUSE_13 = 0xf00d,
+ RADIO_LAST_CALL_FAIL_OEM_CAUSE_14 = 0xf00e,
+ RADIO_LAST_CALL_FAIL_OEM_CAUSE_15 = 0xf00f,
+ RADIO_LAST_CALL_FAIL_ERROR_UNSPECIFIED = 0xffff
+} RADIO_LAST_CALL_FAIL_CAUSE; /* Since 1.4.3 */
+G_STATIC_ASSERT(sizeof(RADIO_LAST_CALL_FAIL_CAUSE) == 4);
+
+typedef enum radio_data_call_fail_cause {
+ RADIO_DATA_CALL_FAIL_NONE = 0,
+ RADIO_DATA_CALL_FAIL_OPERATOR_BARRED = 0x08,
+ RADIO_DATA_CALL_FAIL_NAS_SIGNALLING = 0x0E,
+ RADIO_DATA_CALL_FAIL_LLC_SNDCP = 0x19,
+ RADIO_DATA_CALL_FAIL_INSUFFICIENT_RESOURCES = 0x1A,
+ RADIO_DATA_CALL_FAIL_MISSING_UKNOWN_APN = 0x1B,
+ RADIO_DATA_CALL_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C,
+ RADIO_DATA_CALL_FAIL_USER_AUTHENTICATION = 0x1D,
+ RADIO_DATA_CALL_FAIL_ACTIVATION_REJECT_GGSN = 0x1E,
+ RADIO_DATA_CALL_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F,
+ RADIO_DATA_CALL_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20,
+ RADIO_DATA_CALL_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21,
+ RADIO_DATA_CALL_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22,
+ RADIO_DATA_CALL_FAIL_NSAPI_IN_USE = 0x23,
+ RADIO_DATA_CALL_FAIL_REGULAR_DEACTIVATION = 0x24,
+ RADIO_DATA_CALL_FAIL_QOS_NOT_ACCEPTED = 0x25,
+ RADIO_DATA_CALL_FAIL_NETWORK_FAILURE = 0x26,
+ RADIO_DATA_CALL_FAIL_UMTS_REACTIVATION_REQ = 0x27,
+ RADIO_DATA_CALL_FAIL_FEATURE_NOT_SUPP = 0x28,
+ RADIO_DATA_CALL_FAIL_TFT_SEMANTIC_ERROR = 0x29,
+ RADIO_DATA_CALL_FAIL_TFT_SYTAX_ERROR = 0x2A,
+ RADIO_DATA_CALL_FAIL_UNKNOWN_PDP_CONTEXT = 0x2B,
+ RADIO_DATA_CALL_FAIL_FILTER_SEMANTIC_ERROR = 0x2C,
+ RADIO_DATA_CALL_FAIL_FILTER_SYTAX_ERROR = 0x2D,
+ RADIO_DATA_CALL_FAIL_PDP_WITHOUT_ACTIVE_TFT = 0x2E,
+ RADIO_DATA_CALL_FAIL_ACTIVATION_REJECTED_BCM_VIOLATION = 0x30,
+ RADIO_DATA_CALL_FAIL_ONLY_IPV4_ALLOWED = 0x32,
+ RADIO_DATA_CALL_FAIL_ONLY_IPV6_ALLOWED = 0x33,
+ RADIO_DATA_CALL_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34,
+ RADIO_DATA_CALL_FAIL_ESM_INFO_NOT_RECEIVED = 0x35,
+ RADIO_DATA_CALL_FAIL_PDN_CONN_DOES_NOT_EXIST = 0x36,
+ RADIO_DATA_CALL_FAIL_MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 0x37,
+ RADIO_DATA_CALL_FAIL_COLLISION_WITH_NETWORK_INITIATED_REQUEST = 0x38,
+ RADIO_DATA_CALL_FAIL_ONLY_IPV4V6_ALLOWED = 0x39,
+ RADIO_DATA_CALL_FAIL_ONLY_NON_IP_ALLOWED = 0x3A,
+ RADIO_DATA_CALL_FAIL_UNSUPPORTED_QCI_VALUE = 0x3B,
+ RADIO_DATA_CALL_FAIL_BEARER_HANDLING_NOT_SUPPORTED = 0x3C,
+ RADIO_DATA_CALL_FAIL_MAX_ACTIVE_PDP_CONTEXT_REACHED = 0x41,
+ RADIO_DATA_CALL_FAIL_UNSUPPORTED_APN_IN_CURRENT_PLMN = 0x42,
+ RADIO_DATA_CALL_FAIL_INVALID_TRANSACTION_ID = 0x51,
+ RADIO_DATA_CALL_FAIL_MESSAGE_INCORRECT_SEMANTIC = 0x5F,
+ RADIO_DATA_CALL_FAIL_INVALID_MANDATORY_INFO = 0x60,
+ RADIO_DATA_CALL_FAIL_MESSAGE_TYPE_UNSUPPORTED = 0x61,
+ RADIO_DATA_CALL_FAIL_MSG_TYPE_NONCOMPATIBLE_STATE = 0x62,
+ RADIO_DATA_CALL_FAIL_UNKNOWN_INFO_ELEMENT = 0x63,
+ RADIO_DATA_CALL_FAIL_CONDITIONAL_IE_ERROR = 0x64,
+ RADIO_DATA_CALL_FAIL_MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 0x65,
+ RADIO_DATA_CALL_FAIL_PROTOCOL_ERRORS = 0x6F,
+ RADIO_DATA_CALL_FAIL_APN_TYPE_CONFLICT = 0x70,
+ RADIO_DATA_CALL_FAIL_INVALID_PCSCF_ADDR = 0x71,
+ RADIO_DATA_CALL_FAIL_INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 0x72,
+ RADIO_DATA_CALL_FAIL_EMM_ACCESS_BARRED = 0x73,
+ RADIO_DATA_CALL_FAIL_EMERGENCY_IFACE_ONLY = 0x74,
+ RADIO_DATA_CALL_FAIL_IFACE_MISMATCH = 0x75,
+ RADIO_DATA_CALL_FAIL_COMPANION_IFACE_IN_USE = 0x76,
+ RADIO_DATA_CALL_FAIL_IP_ADDRESS_MISMATCH = 0x77,
+ RADIO_DATA_CALL_FAIL_IFACE_AND_POL_FAMILY_MISMATCH = 0x78,
+ RADIO_DATA_CALL_FAIL_EMM_ACCESS_BARRED_INFINITE_RETRY = 0x79,
+ RADIO_DATA_CALL_FAIL_AUTH_FAILURE_ON_EMERGENCY_CALL = 0x7A,
+ RADIO_DATA_CALL_FAIL_INVALID_DNS_ADDR = 0x7B,
+ RADIO_DATA_CALL_FAIL_INVALID_PCSCF_OR_DNS_ADDRESS = 0x7C,
+ RADIO_DATA_CALL_FAIL_CALL_PREEMPT_BY_EMERGENCY_APN = 0x7F,
+ RADIO_DATA_CALL_FAIL_UE_INITIATED_DETACH_OR_DISCONNECT = 0x80,
+ RADIO_DATA_CALL_FAIL_MIP_FA_REASON_UNSPECIFIED = 0x7D0,
+ RADIO_DATA_CALL_FAIL_MIP_FA_ADMIN_PROHIBITED = 0x7D1,
+ RADIO_DATA_CALL_FAIL_MIP_FA_INSUFFICIENT_RESOURCES = 0x7D2,
+ RADIO_DATA_CALL_FAIL_MIP_FA_MOBILE_NODE_AUTHENTICATION_FAILURE = 0x7D3,
+ RADIO_DATA_CALL_FAIL_MIP_FA_HOME_AGENT_AUTHENTICATION_FAILURE = 0x7D4,
+ RADIO_DATA_CALL_FAIL_MIP_FA_REQUESTED_LIFETIME_TOO_LONG = 0x7D5,
+ RADIO_DATA_CALL_FAIL_MIP_FA_MALFORMED_REQUEST = 0x7D6,
+ RADIO_DATA_CALL_FAIL_MIP_FA_MALFORMED_REPLY = 0x7D7,
+ RADIO_DATA_CALL_FAIL_MIP_FA_ENCAPSULATION_UNAVAILABLE = 0x7D8,
+ RADIO_DATA_CALL_FAIL_MIP_FA_VJ_HEADER_COMPRESSION_UNAVAILABLE = 0x7D9,
+ RADIO_DATA_CALL_FAIL_MIP_FA_REVERSE_TUNNEL_UNAVAILABLE = 0x7DA,
+ RADIO_DATA_CALL_FAIL_MIP_FA_REVERSE_TUNNEL_IS_MANDATORY = 0x7DB,
+ RADIO_DATA_CALL_FAIL_MIP_FA_DELIVERY_STYLE_NOT_SUPPORTED = 0x7DC,
+ RADIO_DATA_CALL_FAIL_MIP_FA_MISSING_NAI = 0x7DD,
+ RADIO_DATA_CALL_FAIL_MIP_FA_MISSING_HOME_AGENT = 0x7DE,
+ RADIO_DATA_CALL_FAIL_MIP_FA_MISSING_HOME_ADDRESS = 0x7DF,
+ RADIO_DATA_CALL_FAIL_MIP_FA_UNKNOWN_CHALLENGE = 0x7E0,
+ RADIO_DATA_CALL_FAIL_MIP_FA_MISSING_CHALLENGE = 0x7E1,
+ RADIO_DATA_CALL_FAIL_MIP_FA_STALE_CHALLENGE = 0x7E2,
+ RADIO_DATA_CALL_FAIL_MIP_HA_REASON_UNSPECIFIED = 0x7E3,
+ RADIO_DATA_CALL_FAIL_MIP_HA_ADMIN_PROHIBITED = 0x7E4,
+ RADIO_DATA_CALL_FAIL_MIP_HA_INSUFFICIENT_RESOURCES = 0x7E5,
+ RADIO_DATA_CALL_FAIL_MIP_HA_MOBILE_NODE_AUTHENTICATION_FAILURE = 0x7E6,
+ RADIO_DATA_CALL_FAIL_MIP_HA_FOREIGN_AGENT_AUTHENTICATION_FAILURE = 0x7E7,
+ RADIO_DATA_CALL_FAIL_MIP_HA_REGISTRATION_ID_MISMATCH = 0x7E8,
+ RADIO_DATA_CALL_FAIL_MIP_HA_MALFORMED_REQUEST = 0x7E9,
+ RADIO_DATA_CALL_FAIL_MIP_HA_UNKNOWN_HOME_AGENT_ADDRESS = 0x7EA,
+ RADIO_DATA_CALL_FAIL_MIP_HA_REVERSE_TUNNEL_UNAVAILABLE = 0x7EB,
+ RADIO_DATA_CALL_FAIL_MIP_HA_REVERSE_TUNNEL_IS_MANDATORY = 0x7EC,
+ RADIO_DATA_CALL_FAIL_MIP_HA_ENCAPSULATION_UNAVAILABLE = 0x7ED,
+ RADIO_DATA_CALL_FAIL_CLOSE_IN_PROGRESS = 0x7EE,
+ RADIO_DATA_CALL_FAIL_NETWORK_INITIATED_TERMINATION = 0x7EF,
+ RADIO_DATA_CALL_FAIL_MODEM_APP_PREEMPTED = 0x7F0,
+ RADIO_DATA_CALL_FAIL_PDN_IPV4_CALL_DISALLOWED = 0x7F1,
+ RADIO_DATA_CALL_FAIL_PDN_IPV4_CALL_THROTTLED = 0x7F2,
+ RADIO_DATA_CALL_FAIL_PDN_IPV6_CALL_DISALLOWED = 0x7F3,
+ RADIO_DATA_CALL_FAIL_PDN_IPV6_CALL_THROTTLED = 0x7F4,
+ RADIO_DATA_CALL_FAIL_MODEM_RESTART = 0x7F5,
+ RADIO_DATA_CALL_FAIL_PDP_PPP_NOT_SUPPORTED = 0x7F6,
+ RADIO_DATA_CALL_FAIL_UNPREFERRED_RAT = 0x7F7,
+ RADIO_DATA_CALL_FAIL_PHYSICAL_LINK_CLOSE_IN_PROGRESS = 0x7F8,
+ RADIO_DATA_CALL_FAIL_APN_PENDING_HANDOVER = 0x7F9,
+ RADIO_DATA_CALL_FAIL_PROFILE_BEARER_INCOMPATIBLE = 0x7FA,
+ RADIO_DATA_CALL_FAIL_SIM_CARD_CHANGED = 0x7FB,
+ RADIO_DATA_CALL_FAIL_LOW_POWER_MODE_OR_POWERING_DOWN = 0x7FC,
+ RADIO_DATA_CALL_FAIL_APN_DISABLED = 0x7FD,
+ RADIO_DATA_CALL_FAIL_MAX_PPP_INACTIVITY_TIMER_EXPIRED = 0x7FE,
+ RADIO_DATA_CALL_FAIL_IPV6_ADDRESS_TRANSFER_FAILED = 0x7FF,
+ RADIO_DATA_CALL_FAIL_TRAT_SWAP_FAILED = 0x800,
+ RADIO_DATA_CALL_FAIL_EHRPD_TO_HRPD_FALLBACK = 0x801,
+ RADIO_DATA_CALL_FAIL_MIP_CONFIG_FAILURE = 0x802,
+ RADIO_DATA_CALL_FAIL_PDN_INACTIVITY_TIMER_EXPIRED = 0x803,
+ RADIO_DATA_CALL_FAIL_MAX_IPV4_CONNECTIONS = 0x804,
+ RADIO_DATA_CALL_FAIL_MAX_IPV6_CONNECTIONS = 0x805,
+ RADIO_DATA_CALL_FAIL_APN_MISMATCH = 0x806,
+ RADIO_DATA_CALL_FAIL_IP_VERSION_MISMATCH = 0x807,
+ RADIO_DATA_CALL_FAIL_DUN_CALL_DISALLOWED = 0x808,
+ RADIO_DATA_CALL_FAIL_INTERNAL_EPC_NONEPC_TRANSITION = 0x809,
+ RADIO_DATA_CALL_FAIL_INTERFACE_IN_USE = 0x80A,
+ RADIO_DATA_CALL_FAIL_APN_DISALLOWED_ON_ROAMING = 0x80B,
+ RADIO_DATA_CALL_FAIL_APN_PARAMETERS_CHANGED = 0x80C,
+ RADIO_DATA_CALL_FAIL_NULL_APN_DISALLOWED = 0x80D,
+ RADIO_DATA_CALL_FAIL_THERMAL_MITIGATION = 0x80E,
+ RADIO_DATA_CALL_FAIL_DATA_SETTINGS_DISABLED = 0x80F,
+ RADIO_DATA_CALL_FAIL_DATA_ROAMING_SETTINGS_DISABLED = 0x810,
+ RADIO_DATA_CALL_FAIL_DDS_SWITCHED = 0x811,
+ RADIO_DATA_CALL_FAIL_FORBIDDEN_APN_NAME = 0x812,
+ RADIO_DATA_CALL_FAIL_DDS_SWITCH_IN_PROGRESS = 0x813,
+ RADIO_DATA_CALL_FAIL_CALL_DISALLOWED_IN_ROAMING = 0x814,
+ RADIO_DATA_CALL_FAIL_NON_IP_NOT_SUPPORTED = 0x815,
+ RADIO_DATA_CALL_FAIL_PDN_NON_IP_CALL_THROTTLED = 0x816,
+ RADIO_DATA_CALL_FAIL_PDN_NON_IP_CALL_DISALLOWED = 0x817,
+ RADIO_DATA_CALL_FAIL_CDMA_LOCK = 0x818,
+ RADIO_DATA_CALL_FAIL_CDMA_INTERCEPT = 0x819,
+ RADIO_DATA_CALL_FAIL_CDMA_REORDER = 0x81A,
+ RADIO_DATA_CALL_FAIL_CDMA_RELEASE_DUE_TO_SO_REJECTION = 0x81B,
+ RADIO_DATA_CALL_FAIL_CDMA_INCOMING_CALL = 0x81C,
+ RADIO_DATA_CALL_FAIL_CDMA_ALERT_STOP = 0x81D,
+ RADIO_DATA_CALL_FAIL_CHANNEL_ACQUISITION_FAILURE = 0x81E,
+ RADIO_DATA_CALL_FAIL_MAX_ACCESS_PROBE = 0x81F,
+ RADIO_DATA_CALL_FAIL_CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STA = 0x820,
+ RADIO_DATA_CALL_FAIL_NO_RESPONSE_FROM_BASE_STATION = 0x821,
+ RADIO_DATA_CALL_FAIL_REJECTED_BY_BASE_STATION = 0x822,
+ RADIO_DATA_CALL_FAIL_CONCURRENT_SERVICES_INCOMPATIBLE = 0x823,
+ RADIO_DATA_CALL_FAIL_NO_CDMA_SERVICE = 0x824,
+ RADIO_DATA_CALL_FAIL_RUIM_NOT_PRESENT = 0x825,
+ RADIO_DATA_CALL_FAIL_CDMA_RETRY_ORDER = 0x826,
+ RADIO_DATA_CALL_FAIL_ACCESS_BLOCK = 0x827,
+ RADIO_DATA_CALL_FAIL_ACCESS_BLOCK_ALL = 0x828,
+ RADIO_DATA_CALL_FAIL_IS707B_MAX_ACCESS_PROBES = 0x829,
+ RADIO_DATA_CALL_FAIL_THERMAL_EMERGENCY = 0x82A,
+ RADIO_DATA_CALL_FAIL_CONCURRENT_SERVICES_NOT_ALLOWED = 0x82B,
+ RADIO_DATA_CALL_FAIL_INCOMING_CALL_REJECTED = 0x82C,
+ RADIO_DATA_CALL_FAIL_NO_SERVICE_ON_GATEWAY = 0x82D,
+ RADIO_DATA_CALL_FAIL_NO_GPRS_CONTEXT = 0x82E,
+ RADIO_DATA_CALL_FAIL_ILLEGAL_MS = 0x82F,
+ RADIO_DATA_CALL_FAIL_ILLEGAL_ME = 0x830,
+ RADIO_DATA_CALL_FAIL_GPRS_SERVICES_AND_NON_GPRS_SERVICES_NOT_ALLOWED = 0x831,
+ RADIO_DATA_CALL_FAIL_GPRS_SERVICES_NOT_ALLOWED = 0x832,
+ RADIO_DATA_CALL_FAIL_MS_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK = 0x833,
+ RADIO_DATA_CALL_FAIL_IMPLICITLY_DETACHED = 0x834,
+ RADIO_DATA_CALL_FAIL_PLMN_NOT_ALLOWED = 0x835,
+ RADIO_DATA_CALL_FAIL_LOCATION_AREA_NOT_ALLOWED = 0x836,
+ RADIO_DATA_CALL_FAIL_GPRS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN = 0x837,
+ RADIO_DATA_CALL_FAIL_PDP_DUPLICATE = 0x838,
+ RADIO_DATA_CALL_FAIL_UE_RAT_CHANGE = 0x839,
+ RADIO_DATA_CALL_FAIL_CONGESTION = 0x83A,
+ RADIO_DATA_CALL_FAIL_NO_PDP_CONTEXT_ACTIVATED = 0x83B,
+ RADIO_DATA_CALL_FAIL_ACCESS_CLASS_DSAC_REJECTION = 0x83C,
+ RADIO_DATA_CALL_FAIL_PDP_ACTIVATE_MAX_RETRY_FAILED = 0x83D,
+ RADIO_DATA_CALL_FAIL_RADIO_ACCESS_BEARER_FAILURE = 0x83E,
+ RADIO_DATA_CALL_FAIL_ESM_UNKNOWN_EPS_BEARER_CONTEXT = 0x83F,
+ RADIO_DATA_CALL_FAIL_DRB_RELEASED_BY_RRC = 0x840,
+ RADIO_DATA_CALL_FAIL_CONNECTION_RELEASED = 0x841,
+ RADIO_DATA_CALL_FAIL_EMM_DETACHED = 0x842,
+ RADIO_DATA_CALL_FAIL_EMM_ATTACH_FAILED = 0x843,
+ RADIO_DATA_CALL_FAIL_EMM_ATTACH_STARTED = 0x844,
+ RADIO_DATA_CALL_FAIL_LTE_NAS_SERVICE_REQUEST_FAILED = 0x845,
+ RADIO_DATA_CALL_FAIL_DUPLICATE_BEARER_ID = 0x846,
+ RADIO_DATA_CALL_FAIL_ESM_COLLISION_SCENARIOS = 0x847,
+ RADIO_DATA_CALL_FAIL_ESM_BEARER_DEACTIVATED_TO_SYNC_WITH_NETWORK = 0x848,
+ RADIO_DATA_CALL_FAIL_ESM_NW_ACTIVATED_DED_BEARER_WITH_ID_OF_DEF_BEARER = 0x849,
+ RADIO_DATA_CALL_FAIL_ESM_BAD_OTA_MESSAGE = 0x84A,
+ RADIO_DATA_CALL_FAIL_ESM_DOWNLOAD_SERVER_REJECTED_THE_CALL = 0x84B,
+ RADIO_DATA_CALL_FAIL_ESM_CONTEXT_TRANSFERRED_DUE_TO_IRAT = 0x84C,
+ RADIO_DATA_CALL_FAIL_DS_EXPLICIT_DEACTIVATION = 0x84D,
+ RADIO_DATA_CALL_FAIL_ESM_LOCAL_CAUSE_NONE = 0x84E,
+ RADIO_DATA_CALL_FAIL_LTE_THROTTLING_NOT_REQUIRED = 0x84F,
+ RADIO_DATA_CALL_FAIL_ACCESS_CONTROL_LIST_CHECK_FAILURE = 0x850,
+ RADIO_DATA_CALL_FAIL_SERVICE_NOT_ALLOWED_ON_PLMN = 0x851,
+ RADIO_DATA_CALL_FAIL_EMM_T3417_EXPIRED = 0x852,
+ RADIO_DATA_CALL_FAIL_EMM_T3417_EXT_EXPIRED = 0x853,
+ RADIO_DATA_CALL_FAIL_RRC_UPLINK_DATA_TRANSMISSION_FAILURE = 0x854,
+ RADIO_DATA_CALL_FAIL_RRC_UPLINK_DELIVERY_FAILED_DUE_TO_HANDOVER = 0x855,
+ RADIO_DATA_CALL_FAIL_RRC_UPLINK_CONNECTION_RELEASE = 0x856,
+ RADIO_DATA_CALL_FAIL_RRC_UPLINK_RADIO_LINK_FAILURE = 0x857,
+ RADIO_DATA_CALL_FAIL_RRC_UPLINK_ERROR_REQUEST_FROM_NAS = 0x858,
+ RADIO_DATA_CALL_FAIL_RRC_CONN_ACCESS_STRATUM_FAILURE = 0x859,
+ RADIO_DATA_CALL_FAIL_RRC_CONN_ANOTHER_PROCEDURE_IN_PROGRESS = 0x85A,
+ RADIO_DATA_CALL_FAIL_RRC_CONN_ACCESS_BARRED = 0x85B,
+ RADIO_DATA_CALL_FAIL_RRC_CONN_CELL_RESELECTION = 0x85C,
+ RADIO_DATA_CALL_FAIL_RRC_CONN_CONFIG_FAILURE = 0x85D,
+ RADIO_DATA_CALL_FAIL_RRC_CONN_TIMER_EXPIRED = 0x85E,
+ RADIO_DATA_CALL_FAIL_RRC_CONN_LINK_FAILURE = 0x85F,
+ RADIO_DATA_CALL_FAIL_RRC_CONN_CELL_NOT_CAMPED = 0x860,
+ RADIO_DATA_CALL_FAIL_RRC_CONN_SYSTEM_INTERVAL_FAILURE = 0x861,
+ RADIO_DATA_CALL_FAIL_RRC_CONN_REJECT_BY_NETWORK = 0x862,
+ RADIO_DATA_CALL_FAIL_RRC_CONN_NORMAL_RELEASE = 0x863,
+ RADIO_DATA_CALL_FAIL_RRC_CONN_RADIO_LINK_FAILURE = 0x864,
+ RADIO_DATA_CALL_FAIL_RRC_CONN_REESTABLISHMENT_FAILURE = 0x865,
+ RADIO_DATA_CALL_FAIL_RRC_CONN_OUT_OF_SERVICE_DURING_CELL_REGISTER = 0x866,
+ RADIO_DATA_CALL_FAIL_RRC_CONN_ABORT_REQUEST = 0x867,
+ RADIO_DATA_CALL_FAIL_RRC_CONN_SYSTEM_INFORMATION_BLOCK_READ_ERROR = 0x868,
+ RADIO_DATA_CALL_FAIL_NETWORK_INITIATED_DETACH_WITH_AUTO_REATTACH = 0x869,
+ RADIO_DATA_CALL_FAIL_NETWORK_INITIATED_DETACH_NO_AUTO_REATTACH = 0x86A,
+ RADIO_DATA_CALL_FAIL_ESM_PROCEDURE_TIME_OUT = 0x86B,
+ RADIO_DATA_CALL_FAIL_INVALID_CONNECTION_ID = 0x86C,
+ RADIO_DATA_CALL_FAIL_MAXIMIUM_NSAPIS_EXCEEDED = 0x86D,
+ RADIO_DATA_CALL_FAIL_INVALID_PRIMARY_NSAPI = 0x86E,
+ RADIO_DATA_CALL_FAIL_CANNOT_ENCODE_OTA_MESSAGE = 0x86F,
+ RADIO_DATA_CALL_FAIL_RADIO_ACCESS_BEARER_SETUP_FAILURE = 0x870,
+ RADIO_DATA_CALL_FAIL_PDP_ESTABLISH_TIMEOUT_EXPIRED = 0x871,
+ RADIO_DATA_CALL_FAIL_PDP_MODIFY_TIMEOUT_EXPIRED = 0x872,
+ RADIO_DATA_CALL_FAIL_PDP_INACTIVE_TIMEOUT_EXPIRED = 0x873,
+ RADIO_DATA_CALL_FAIL_PDP_LOWERLAYER_ERROR = 0x874,
+ RADIO_DATA_CALL_FAIL_PDP_MODIFY_COLLISION = 0x875,
+ RADIO_DATA_CALL_FAIL_MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 0x876,
+ RADIO_DATA_CALL_FAIL_NAS_REQUEST_REJECTED_BY_NETWORK = 0x877,
+ RADIO_DATA_CALL_FAIL_RRC_CONNECTION_INVALID_REQUEST = 0x878,
+ RADIO_DATA_CALL_FAIL_RRC_CONNECTION_TRACKING_AREA_ID_CHANGED = 0x879,
+ RADIO_DATA_CALL_FAIL_RRC_CONNECTION_RF_UNAVAILABLE = 0x87A,
+ RADIO_DATA_CALL_FAIL_RRC_CONNECTION_ABORTED_DUE_TO_IRAT_CHANGE = 0x87B,
+ RADIO_DATA_CALL_FAIL_RRC_CONNECTION_RELEASED_SECURITY_NOT_ACTIVE = 0x87C,
+ RADIO_DATA_CALL_FAIL_RRC_CONNECTION_ABORTED_AFTER_HANDOVER = 0x87D,
+ RADIO_DATA_CALL_FAIL_RRC_CONNECTION_ABORTED_AFTER_IRAT_CELL_CHANGE = 0x87E,
+ RADIO_DATA_CALL_FAIL_RRC_CONNECTION_ABORTED_DURING_IRAT_CELL_CHANGE = 0x87F,
+ RADIO_DATA_CALL_FAIL_IMSI_UNKNOWN_IN_HOME_SUBSCRIBER_SERVER = 0x880,
+ RADIO_DATA_CALL_FAIL_IMEI_NOT_ACCEPTED = 0x881,
+ RADIO_DATA_CALL_FAIL_EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED = 0x882,
+ RADIO_DATA_CALL_FAIL_EPS_SERVICES_NOT_ALLOWED_IN_PLMN = 0x883,
+ RADIO_DATA_CALL_FAIL_MSC_TEMPORARILY_NOT_REACHABLE = 0x884,
+ RADIO_DATA_CALL_FAIL_CS_DOMAIN_NOT_AVAILABLE = 0x885,
+ RADIO_DATA_CALL_FAIL_ESM_FAILURE = 0x886,
+ RADIO_DATA_CALL_FAIL_MAC_FAILURE = 0x887,
+ RADIO_DATA_CALL_FAIL_SYNCHRONIZATION_FAILURE = 0x888,
+ RADIO_DATA_CALL_FAIL_UE_SECURITY_CAPABILITIES_MISMATCH = 0x889,
+ RADIO_DATA_CALL_FAIL_SECURITY_MODE_REJECTED = 0x88A,
+ RADIO_DATA_CALL_FAIL_UNACCEPTABLE_NON_EPS_AUTHENTICATION = 0x88B,
+ RADIO_DATA_CALL_FAIL_CS_FALLBACK_CALL_ESTABLISHMENT_NOT_ALLOWED = 0x88C,
+ RADIO_DATA_CALL_FAIL_NO_EPS_BEARER_CONTEXT_ACTIVATED = 0x88D,
+ RADIO_DATA_CALL_FAIL_INVALID_EMM_STATE = 0x88E,
+ RADIO_DATA_CALL_FAIL_NAS_LAYER_FAILURE = 0x88F,
+ RADIO_DATA_CALL_FAIL_MULTIPLE_PDP_CALL_NOT_ALLOWED = 0x890,
+ RADIO_DATA_CALL_FAIL_EMBMS_NOT_ENABLED = 0x891,
+ RADIO_DATA_CALL_FAIL_IRAT_HANDOVER_FAILED = 0x892,
+ RADIO_DATA_CALL_FAIL_EMBMS_REGULAR_DEACTIVATION = 0x893,
+ RADIO_DATA_CALL_FAIL_TEST_LOOPBACK_REGULAR_DEACTIVATION = 0x894,
+ RADIO_DATA_CALL_FAIL_LOWER_LAYER_REGISTRATION_FAILURE = 0x895,
+ RADIO_DATA_CALL_FAIL_DATA_PLAN_EXPIRED = 0x896,
+ RADIO_DATA_CALL_FAIL_UMTS_HANDOVER_TO_IWLAN = 0x897,
+ RADIO_DATA_CALL_FAIL_EVDO_CONN_DENY_BY_GENERAL_OR_NETWORK_BUSY = 0x898,
+ RADIO_DATA_CALL_FAIL_EVDO_CONN_DENY_BY_BILLING_OR_AUTH_FAILURE = 0x899,
+ RADIO_DATA_CALL_FAIL_EVDO_HDR_CHANGED = 0x89A,
+ RADIO_DATA_CALL_FAIL_EVDO_HDR_EXITED = 0x89B,
+ RADIO_DATA_CALL_FAIL_EVDO_HDR_NO_SESSION = 0x89C,
+ RADIO_DATA_CALL_FAIL_EVDO_USING_GPS_FIX_INSTEAD_OF_HDR_CALL = 0x89D,
+ RADIO_DATA_CALL_FAIL_EVDO_HDR_CONNECTION_SETUP_TIMEOUT = 0x89E,
+ RADIO_DATA_CALL_FAIL_FAILED_TO_ACQUIRE_COLOCATED_HDR = 0x89F,
+ RADIO_DATA_CALL_FAIL_OTASP_COMMIT_IN_PROGRESS = 0x8A0,
+ RADIO_DATA_CALL_FAIL_NO_HYBRID_HDR_SERVICE = 0x8A1,
+ RADIO_DATA_CALL_FAIL_HDR_NO_LOCK_GRANTED = 0x8A2,
+ RADIO_DATA_CALL_FAIL_DBM_OR_SMS_IN_PROGRESS = 0x8A3,
+ RADIO_DATA_CALL_FAIL_HDR_FADE = 0x8A4,
+ RADIO_DATA_CALL_FAIL_HDR_ACCESS_FAILURE = 0x8A5,
+ RADIO_DATA_CALL_FAIL_UNSUPPORTED_1X_PREV = 0x8A6,
+ RADIO_DATA_CALL_FAIL_LOCAL_END = 0x8A7,
+ RADIO_DATA_CALL_FAIL_NO_SERVICE = 0x8A8,
+ RADIO_DATA_CALL_FAIL_FADE = 0x8A9,
+ RADIO_DATA_CALL_FAIL_NORMAL_RELEASE = 0x8AA,
+ RADIO_DATA_CALL_FAIL_ACCESS_ATTEMPT_ALREADY_IN_PROGRESS = 0x8AB,
+ RADIO_DATA_CALL_FAIL_REDIRECTION_OR_HANDOFF_IN_PROGRESS = 0x8AC,
+ RADIO_DATA_CALL_FAIL_EMERGENCY_MODE = 0x8AD,
+ RADIO_DATA_CALL_FAIL_PHONE_IN_USE = 0x8AE,
+ RADIO_DATA_CALL_FAIL_INVALID_MODE = 0x8AF,
+ RADIO_DATA_CALL_FAIL_INVALID_SIM_STATE = 0x8B0,
+ RADIO_DATA_CALL_FAIL_NO_COLLOCATED_HDR = 0x8B1,
+ RADIO_DATA_CALL_FAIL_UE_IS_ENTERING_POWERSAVE_MODE = 0x8B2,
+ RADIO_DATA_CALL_FAIL_DUAL_SWITCH = 0x8B3,
+ RADIO_DATA_CALL_FAIL_PPP_TIMEOUT = 0x8B4,
+ RADIO_DATA_CALL_FAIL_PPP_AUTH_FAILURE = 0x8B5,
+ RADIO_DATA_CALL_FAIL_PPP_OPTION_MISMATCH = 0x8B6,
+ RADIO_DATA_CALL_FAIL_PPP_PAP_FAILURE = 0x8B7,
+ RADIO_DATA_CALL_FAIL_PPP_CHAP_FAILURE = 0x8B8,
+ RADIO_DATA_CALL_FAIL_PPP_CLOSE_IN_PROGRESS = 0x8B9,
+ RADIO_DATA_CALL_FAIL_LIMITED_TO_IPV4 = 0x8BA,
+ RADIO_DATA_CALL_FAIL_LIMITED_TO_IPV6 = 0x8BB,
+ RADIO_DATA_CALL_FAIL_VSNCP_TIMEOUT = 0x8BC,
+ RADIO_DATA_CALL_FAIL_VSNCP_GEN_ERROR = 0x8BD,
+ RADIO_DATA_CALL_FAIL_VSNCP_APN_UNATHORIZED = 0x8BE,
+ RADIO_DATA_CALL_FAIL_VSNCP_PDN_LIMIT_EXCEEDED = 0x8BF,
+ RADIO_DATA_CALL_FAIL_VSNCP_NO_PDN_GATEWAY_ADDRESS = 0x8C0,
+ RADIO_DATA_CALL_FAIL_VSNCP_PDN_GATEWAY_UNREACHABLE = 0x8C1,
+ RADIO_DATA_CALL_FAIL_VSNCP_PDN_GATEWAY_REJECT = 0x8C2,
+ RADIO_DATA_CALL_FAIL_VSNCP_INSUFFICIENT_PARAMETERS = 0x8C3,
+ RADIO_DATA_CALL_FAIL_VSNCP_RESOURCE_UNAVAILABLE = 0x8C4,
+ RADIO_DATA_CALL_FAIL_VSNCP_ADMINISTRATIVELY_PROHIBITED = 0x8C5,
+ RADIO_DATA_CALL_FAIL_VSNCP_PDN_ID_IN_USE = 0x8C6,
+ RADIO_DATA_CALL_FAIL_VSNCP_SUBSCRIBER_LIMITATION = 0x8C7,
+ RADIO_DATA_CALL_FAIL_VSNCP_PDN_EXISTS_FOR_THIS_APN = 0x8C8,
+ RADIO_DATA_CALL_FAIL_VSNCP_RECONNECT_NOT_ALLOWED = 0x8C9,
+ RADIO_DATA_CALL_FAIL_IPV6_PREFIX_UNAVAILABLE = 0x8CA,
+ RADIO_DATA_CALL_FAIL_HANDOFF_PREFERENCE_CHANGED = 0x8CB,
+ RADIO_DATA_CALL_FAIL_OEM_DCFAILCAUSE_1 = 0x1001,
+ RADIO_DATA_CALL_FAIL_OEM_DCFAILCAUSE_2 = 0x1002,
+ RADIO_DATA_CALL_FAIL_OEM_DCFAILCAUSE_3 = 0x1003,
+ RADIO_DATA_CALL_FAIL_OEM_DCFAILCAUSE_4 = 0x1004,
+ RADIO_DATA_CALL_FAIL_OEM_DCFAILCAUSE_5 = 0x1005,
+ RADIO_DATA_CALL_FAIL_OEM_DCFAILCAUSE_6 = 0x1006,
+ RADIO_DATA_CALL_FAIL_OEM_DCFAILCAUSE_7 = 0x1007,
+ RADIO_DATA_CALL_FAIL_OEM_DCFAILCAUSE_8 = 0x1008,
+ RADIO_DATA_CALL_FAIL_OEM_DCFAILCAUSE_9 = 0x1009,
+ RADIO_DATA_CALL_FAIL_OEM_DCFAILCAUSE_10 = 0x100A,
+ RADIO_DATA_CALL_FAIL_OEM_DCFAILCAUSE_11 = 0x100B,
+ RADIO_DATA_CALL_FAIL_OEM_DCFAILCAUSE_12 = 0x100C,
+ RADIO_DATA_CALL_FAIL_OEM_DCFAILCAUSE_13 = 0x100D,
+ RADIO_DATA_CALL_FAIL_OEM_DCFAILCAUSE_14 = 0x100E,
+ RADIO_DATA_CALL_FAIL_OEM_DCFAILCAUSE_15 = 0x100F,
+ RADIO_DATA_CALL_FAIL_VOICE_REGISTRATION_FAIL = -1,
+ RADIO_DATA_CALL_FAIL_DATA_REGISTRATION_FAIL = -2,
+ RADIO_DATA_CALL_FAIL_SIGNAL_LOST = -3,
+ RADIO_DATA_CALL_FAIL_PREF_RADIO_TECH_CHANGED = -4,
+ RADIO_DATA_CALL_FAIL_RADIO_POWER_OFF = -5,
+ RADIO_DATA_CALL_FAIL_TETHERED_CALL_ACTIVE = -6,
+ RADIO_DATA_CALL_FAIL_UNSPECIFIED = 0xffff
+} RADIO_DATA_CALL_FAIL_CAUSE; /* Since 1.4.3 */
+G_STATIC_ASSERT(sizeof(RADIO_DATA_CALL_FAIL_CAUSE) == 4);
+
typedef struct radio_response_info {
RADIO_RESP_TYPE type RADIO_ALIGNED(4);
guint32 serial RADIO_ALIGNED(4);
- guint32 error RADIO_ALIGNED(4);
+ RADIO_ERROR error RADIO_ALIGNED(4);
} RadioResponseInfo;
G_STATIC_ASSERT(sizeof(RadioResponseInfo) == 12);
@@ -436,6 +1343,12 @@
} RADIO_ALIGNED(8) RadioCardStatus_1_4; /* Since 1.4.0 */
G_STATIC_ASSERT(sizeof(RadioCardStatus_1_4) == 96);
+typedef struct radio_card_status_1_5 {
+ RadioCardStatus_1_4 base RADIO_ALIGNED(8);
+ GBinderHidlVec applications RADIO_ALIGNED(8);
+} RADIO_ALIGNED(8) RadioCardStatus_1_5; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioCardStatus_1_5) == 112);
+
typedef struct radio_app_status {
RADIO_APP_TYPE appType RADIO_ALIGNED(4);
RADIO_APP_STATE appState RADIO_ALIGNED(4);
@@ -480,13 +1393,13 @@
typedef struct radio_dial {
GBinderHidlString address RADIO_ALIGNED(8);
- gint32 clir RADIO_ALIGNED(4);
+ RADIO_CLIR clir RADIO_ALIGNED(4);
GBinderHidlVec uusInfo RADIO_ALIGNED(8); /* vec<RadioUusInfo> */
} RADIO_ALIGNED(8) RadioDial;
G_STATIC_ASSERT(sizeof(RadioDial) == 40);
typedef struct radio_last_call_fail_cause_info {
- gint32 causeCode RADIO_ALIGNED(4);
+ RADIO_LAST_CALL_FAIL_CAUSE causeCode RADIO_ALIGNED(4);
GBinderHidlString vendorCause RADIO_ALIGNED(8);
} RADIO_ALIGNED(8) RadioLastCallFailCauseInfo;
G_STATIC_ASSERT(sizeof(RadioLastCallFailCauseInfo) == 24);
@@ -541,11 +1454,33 @@
} RADIO_ALIGNED(8) RadioDataProfile_1_4; /* Since 1.2.5 */
G_STATIC_ASSERT(sizeof(RadioDataProfile_1_4) == 112);
+typedef struct radio_data_profile_1_5 {
+ RADIO_DATA_PROFILE_ID profileId RADIO_ALIGNED(4);
+ GBinderHidlString apn RADIO_ALIGNED(8);
+ RADIO_PDP_PROTOCOL_TYPE protocol RADIO_ALIGNED(4);
+ RADIO_PDP_PROTOCOL_TYPE roamingProtocol RADIO_ALIGNED(4);
+ RADIO_APN_AUTH_TYPE authType RADIO_ALIGNED(4);
+ GBinderHidlString user RADIO_ALIGNED(8);
+ GBinderHidlString password RADIO_ALIGNED(8);
+ RADIO_DATA_PROFILE_TYPE type RADIO_ALIGNED(4);
+ gint32 maxConnsTime RADIO_ALIGNED(4);
+ gint32 maxConns RADIO_ALIGNED(4);
+ gint32 waitTime RADIO_ALIGNED(4);
+ guint8 enabled RADIO_ALIGNED(1);
+ RADIO_APN_TYPES supportedApnTypesBitmap RADIO_ALIGNED(4);
+ RADIO_ACCESS_FAMILY bearerBitmap RADIO_ALIGNED(4);
+ gint32 mtuV4 RADIO_ALIGNED(4);
+ gint32 mtuV6 RADIO_ALIGNED(4);
+ guint8 preferred RADIO_ALIGNED(1);
+ guint8 persistent RADIO_ALIGNED(1);
+} RADIO_ALIGNED(8) RadioDataProfile_1_5; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioDataProfile_1_5) == 112);
+
typedef struct radio_data_call {
- gint32 status RADIO_ALIGNED(4);
+ RADIO_DATA_CALL_FAIL_CAUSE status RADIO_ALIGNED(4);
gint32 suggestedRetryTime RADIO_ALIGNED(4);
gint32 cid RADIO_ALIGNED(4);
- gint32 active RADIO_ALIGNED(4);
+ RADIO_DATA_CALL_ACTIVE_STATUS active RADIO_ALIGNED(4);
GBinderHidlString type RADIO_ALIGNED(8);
GBinderHidlString ifname RADIO_ALIGNED(8);
GBinderHidlString addresses RADIO_ALIGNED(8);
@@ -557,10 +1492,10 @@
G_STATIC_ASSERT(sizeof(RadioDataCall) == 120);
typedef struct radio_data_call_1_4 {
- gint32 cause RADIO_ALIGNED(4);
+ RADIO_DATA_CALL_FAIL_CAUSE cause RADIO_ALIGNED(4);
gint32 suggestedRetryTime RADIO_ALIGNED(4);
gint32 cid RADIO_ALIGNED(4);
- gint32 active RADIO_ALIGNED(4);
+ RADIO_DATA_CALL_ACTIVE_STATUS active RADIO_ALIGNED(4);
RADIO_PDP_PROTOCOL_TYPE type RADIO_ALIGNED(4);
GBinderHidlString ifname RADIO_ALIGNED(8);
GBinderHidlVec addresses RADIO_ALIGNED(8); /* vec<GBinderHidlString> */
@@ -571,7 +1506,29 @@
} RADIO_ALIGNED(8) RadioDataCall_1_4; /* Since 1.2.5 */
G_STATIC_ASSERT(sizeof(RadioDataCall_1_4) == 112);
-#define DATA_CALL_VERSION (11)
+typedef struct radio_link_address {
+ GBinderHidlString address RADIO_ALIGNED(8);
+ gint32 properties RADIO_ALIGNED(4);
+ guint64 deprecationTime RADIO_ALIGNED(8);
+ guint64 expirationTime RADIO_ALIGNED(8);
+} RADIO_ALIGNED(8) RadioLinkAddress; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioLinkAddress) == 40);
+
+typedef struct radio_data_call_1_5 {
+ RADIO_DATA_CALL_FAIL_CAUSE cause RADIO_ALIGNED(4);
+ gint32 suggestedRetryTime RADIO_ALIGNED(4);
+ gint32 cid RADIO_ALIGNED(4);
+ RADIO_DATA_CALL_ACTIVE_STATUS active RADIO_ALIGNED(4);
+ RADIO_PDP_PROTOCOL_TYPE type RADIO_ALIGNED(4);
+ GBinderHidlString ifname RADIO_ALIGNED(8);
+ GBinderHidlVec addresses RADIO_ALIGNED(8); /* vec<RadioLinkAddress> */
+ GBinderHidlVec dnses RADIO_ALIGNED(8); /* vec<GBinderHidlString> */
+ GBinderHidlVec gateways RADIO_ALIGNED(8); /* vec<GBinderHidlString> */
+ GBinderHidlVec pcscf RADIO_ALIGNED(8); /* vec<GBinderHidlString> */
+ gint32 mtuV4 RADIO_ALIGNED(4);
+ gint32 mtuV6 RADIO_ALIGNED(4);
+} RADIO_ALIGNED(8) RadioDataCall_1_5; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioDataCall_1_5) == 112);
typedef struct radio_sms_write_args {
gint32 status RADIO_ALIGNED(4);
@@ -593,6 +1550,15 @@
} RADIO_ALIGNED(8) RadioSendSmsResult;
G_STATIC_ASSERT(sizeof(RadioSendSmsResult) == 32);
+typedef struct radio_ims_sms_message {
+ RADIO_TECH_FAMILY tech RADIO_ALIGNED(4);
+ gboolean retry RADIO_ALIGNED(1);
+ gint32 messageRef RADIO_ALIGNED(4);
+ GBinderHidlVec cdmaMessage RADIO_ALIGNED(8); /* vec<CdmaSmsMessage> */
+ GBinderHidlVec gsmMessage RADIO_ALIGNED(8); /* vec<RadioGsmSmsMessage> */
+} RADIO_ALIGNED(8) RadioImsSmsMessage; /* Since 1.4.9 */
+G_STATIC_ASSERT(sizeof(RadioImsSmsMessage) == 48);
+
typedef struct radio_icc_io {
gint32 command RADIO_ALIGNED(4);
gint32 fileId RADIO_ALIGNED(4);
@@ -625,7 +1591,7 @@
G_STATIC_ASSERT(sizeof(RadioIccIoResult) == 24);
typedef struct radio_call_forward_info {
- gint32 status RADIO_ALIGNED(4);
+ RADIO_CALL_FORWARD status RADIO_ALIGNED(4);
gint32 reason RADIO_ALIGNED(4);
gint32 serviceClass RADIO_ALIGNED(4);
gint32 toa RADIO_ALIGNED(4);
@@ -684,11 +1650,11 @@
guint8 registered RADIO_ALIGNED(1);
gint32 timeStampType RADIO_ALIGNED(4);
guint64 timeStamp RADIO_ALIGNED(8);
- GBinderHidlVec gsm RADIO_ALIGNED(8); /* vec<RadioCellInfoGsm> */
- GBinderHidlVec cdma RADIO_ALIGNED(8); /* vec<RadioCellInfoCdma> */
- GBinderHidlVec lte RADIO_ALIGNED(8); /* vec<RadioCellInfoLte> */
- GBinderHidlVec wcdma RADIO_ALIGNED(8); /* vec<RadioCellInfoWcdma> */
- GBinderHidlVec tdscdma RADIO_ALIGNED(8); /* vec<RadioCellInfoTdscdma> */
+ GBinderHidlVec gsm RADIO_ALIGNED(8); /* vec<RadioCellInfoGsm_1_2> */
+ GBinderHidlVec cdma RADIO_ALIGNED(8); /* vec<RadioCellInfoCdma_1_2> */
+ GBinderHidlVec lte RADIO_ALIGNED(8); /* vec<RadioCellInfoLte_1_2> */
+ GBinderHidlVec wcdma RADIO_ALIGNED(8); /* vec<RadioCellInfoWcdma_1_2> */
+ GBinderHidlVec tdscdma RADIO_ALIGNED(8); /* vec<RadioCellInfoTdscdma_1_2> */
RADIO_CELL_CONNECTION_STATUS connectionStatus RADIO_ALIGNED(4);
} RADIO_ALIGNED(8) RadioCellInfo_1_2; /* Since 1.2.0 */
G_STATIC_ASSERT(sizeof(RadioCellInfo_1_2) == 112);
@@ -715,6 +1681,12 @@
} RADIO_ALIGNED(8) RadioCellIdentityGsm_1_2; /* Since 1.2.3 */
G_STATIC_ASSERT(sizeof(RadioCellIdentityGsm_1_2) == 80);
+typedef struct radio_cell_identity_gsm_1_5 {
+ RadioCellIdentityGsm_1_2 base RADIO_ALIGNED(8);
+ GBinderHidlVec additionalPlmns RADIO_ALIGNED(8); /* vec<GBinderHidlString> */
+} RADIO_ALIGNED(8) RadioCellIdentityGsm_1_5; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioCellIdentityGsm_1_5) == 96);
+
typedef struct radio_cell_identity_wcdma {
GBinderHidlString mcc RADIO_ALIGNED(8);
GBinderHidlString mnc RADIO_ALIGNED(8);
@@ -731,6 +1703,23 @@
} RADIO_ALIGNED(8) RadioCellIdentityWcdma_1_2; /* Since 1.2.3 */
G_STATIC_ASSERT(sizeof(RadioCellIdentityWcdma_1_2) == 80);
+typedef struct radio_closed_subscriber_group_info {
+ gboolean csgIndication RADIO_ALIGNED(1);
+ GBinderHidlString homeNodebName RADIO_ALIGNED(8);
+ gint32 csgIdentity RADIO_ALIGNED(4);
+} RADIO_ALIGNED(8) RadioClosedSubscriberGroupInfo; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioClosedSubscriberGroupInfo) == 32);
+
+typedef struct radio_cell_identity_wcdma_1_5 {
+ RadioCellIdentityWcdma_1_2 base RADIO_ALIGNED(8);
+ GBinderHidlVec additionalPlmns RADIO_ALIGNED(8); /* vec<GBinderHidlString> */
+ guint8 csgInfoAvailable RADIO_ALIGNED(1);
+ union {
+ RadioClosedSubscriberGroupInfo gsm RADIO_ALIGNED(8);
+ } optionalCsgInfo RADIO_ALIGNED(8);
+} RADIO_ALIGNED(8) RadioCellIdentityWcdma_1_5; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioCellIdentityWcdma_1_5) == 136);
+
typedef struct radio_cell_identity_cdma {
gint32 networkId RADIO_ALIGNED(4);
gint32 systemId RADIO_ALIGNED(4);
@@ -763,6 +1752,17 @@
} RADIO_ALIGNED(8) RadioCellIdentityLte_1_2; /* Since 1.2.3 */
G_STATIC_ASSERT(sizeof(RadioCellIdentityLte_1_2) == 88);
+typedef struct radio_cell_identity_lte_1_5 {
+ RadioCellIdentityLte_1_2 base RADIO_ALIGNED(8);
+ GBinderHidlVec additionalPlmns RADIO_ALIGNED(8); /* vec<GBinderHidlString> */
+ guint8 csgInfoAvailable RADIO_ALIGNED(1);
+ union {
+ RadioClosedSubscriberGroupInfo gsm RADIO_ALIGNED(8);
+ } optionalCsgInfo RADIO_ALIGNED(8);
+ GBinderHidlVec bands RADIO_ALIGNED(8); /* vec<EutranBands> */
+} RADIO_ALIGNED(8) RadioCellIdentityLte_1_5; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioCellIdentityLte_1_5) == 160);
+
typedef struct radio_cell_identity_tdscdma {
GBinderHidlString mcc RADIO_ALIGNED(8);
GBinderHidlString mnc RADIO_ALIGNED(8);
@@ -779,6 +1779,16 @@
} RADIO_ALIGNED(8) RadioCellIdentityTdscdma_1_2; /* Since 1.2.3 */
G_STATIC_ASSERT(sizeof(RadioCellIdentityTdscdma_1_2) == 88);
+typedef struct radio_cell_identity_tdscdma_1_5 {
+ RadioCellIdentityTdscdma_1_2 base RADIO_ALIGNED(8);
+ GBinderHidlVec additionalPlmns RADIO_ALIGNED(8); /* vec<GBinderHidlString> */
+ guint8 csgInfoAvailable RADIO_ALIGNED(1);
+ union {
+ RadioClosedSubscriberGroupInfo gsm RADIO_ALIGNED(8);
+ } optionalCsgInfo RADIO_ALIGNED(8);
+} RADIO_ALIGNED(8) RadioCellIdentityTdscdma_1_5; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioCellIdentityTdscdma_1_5) == 144);
+
typedef struct radio_cell_identity_nr {
GBinderHidlString mcc RADIO_ALIGNED(8);
GBinderHidlString mnc RADIO_ALIGNED(8);
@@ -790,6 +1800,26 @@
} RADIO_ALIGNED(8) RadioCellIdentityNr; /* Since 1.2.5 */
G_STATIC_ASSERT(sizeof(RadioCellIdentityNr) == 88);
+typedef struct radio_cell_identity_nr_1_5 {
+ RadioCellIdentityNr base RADIO_ALIGNED(8);
+ GBinderHidlVec additionalPlmns RADIO_ALIGNED(8); /* vec<GBinderHidlString> */
+ GBinderHidlVec bands RADIO_ALIGNED(8); /* vec<NgranBands> */
+} RADIO_ALIGNED(8) RadioCellIdentityNr_1_5; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioCellIdentityNr_1_5) == 120);
+
+typedef struct radio_cell_identity_1_5 {
+ guint8 cellIdentityType RADIO_ALIGNED(1); /* RADIO_CELL_IDENTITY_TYPE_1_5 */
+ union {
+ RadioCellIdentityGsm_1_5 gsm RADIO_ALIGNED(8);
+ RadioCellIdentityWcdma_1_5 wcdma RADIO_ALIGNED(8);
+ RadioCellIdentityTdscdma_1_5 tdscdma RADIO_ALIGNED(8);
+ RadioCellIdentityCdma_1_2 cdma RADIO_ALIGNED(8);
+ RadioCellIdentityLte_1_5 lte RADIO_ALIGNED(8);
+ RadioCellIdentityNr_1_5 nr RADIO_ALIGNED(8);
+ } RADIO_ALIGNED(8) identity;
+} RADIO_ALIGNED(8) RadioCellIdentity_1_5; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioCellIdentity_1_5) == 168);
+
typedef struct radio_voice_reg_state_result {
RADIO_REG_STATE regState RADIO_ALIGNED(4);
RADIO_TECH rat RADIO_ALIGNED(4);
@@ -833,10 +1863,17 @@
G_STATIC_ASSERT(sizeof(RadioDataRegStateResult_1_2) == 104);
typedef struct radio_data_reg_lte_vops_info {
- guint32 isVopsSupported RADIO_ALIGNED(4);
- guint32 isEmcBearerSupported RADIO_ALIGNED(4);
-} RADIO_ALIGNED(4) RadioDataRegLteVopsInfo; /* Since 1.4.0 */
-G_STATIC_ASSERT(sizeof(RadioDataRegLteVopsInfo) == 8);
+ guint8 isVopsSupported RADIO_ALIGNED(1);
+ guint8 isEmcBearerSupported RADIO_ALIGNED(1);
+} RADIO_ALIGNED(1) RadioDataRegLteVopsInfo; /* Since 1.4.12 */
+G_STATIC_ASSERT(sizeof(RadioDataRegLteVopsInfo) == 2);
+
+typedef struct radio_data_reg_nr_inicators {
+ guint8 isEndcAvailable RADIO_ALIGNED(1);
+ guint8 isDcNrRestricted RADIO_ALIGNED(1);
+ guint8 isNrAvailable RADIO_ALIGNED(1);
+} RADIO_ALIGNED(1) RadioDataRegNrIndicators; /* Since 1.4.12 */
+G_STATIC_ASSERT(sizeof(RadioDataRegNrIndicators) == 3);
typedef struct radio_data_reg_state_result_1_4 {
RADIO_REG_STATE regState RADIO_ALIGNED(4);
@@ -844,10 +1881,40 @@
gint32 reasonDataDenied RADIO_ALIGNED(4);
gint32 maxDataCalls RADIO_ALIGNED(4);
RadioCellIdentity_1_2 cellIdentity RADIO_ALIGNED(8);
- RadioDataRegLteVopsInfo lteVopsInfo RADIO_ALIGNED(4);
-} RADIO_ALIGNED(8) RadioDataRegStateResult_1_4; /* Since 1.4.0 */
+ guint8 lteVopsInfoValid RADIO_ALIGNED(1);
+ RadioDataRegLteVopsInfo lteVopsInfo RADIO_ALIGNED(1);
+ RadioDataRegNrIndicators nrIndicators RADIO_ALIGNED(1);
+} RADIO_ALIGNED(8) RadioDataRegStateResult_1_4; /* Since 1.4.12 */
G_STATIC_ASSERT(sizeof(RadioDataRegStateResult_1_4) == 112);
+typedef struct radio_reg_cdma2000_registration_info {
+ guint8 cssSupported RADIO_ALIGNED(1);
+ gint32 roamingIndicator RADIO_ALIGNED(4);
+ gint32 systemIsInPrl RADIO_ALIGNED(4);
+ gint32 defaultRoamingIndicator RADIO_ALIGNED(4);
+} RADIO_ALIGNED(4) RadioRegCdma2000RegistrationInfo; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioRegCdma2000RegistrationInfo) == 16);
+
+typedef struct radio_reg_eutran_registration_info {
+ RadioDataRegLteVopsInfo lteVopsInfo RADIO_ALIGNED(1);
+ RadioDataRegNrIndicators nrIndicators RADIO_ALIGNED(1);
+} RADIO_ALIGNED(1) RadioRegEutranRegistrationInfo; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioRegEutranRegistrationInfo) == 5);
+
+typedef struct radio_reg_state_result_1_5 {
+ RADIO_REG_STATE regState RADIO_ALIGNED(4);
+ RADIO_TECH rat RADIO_ALIGNED(4);
+ gint32 reasonDataDenied RADIO_ALIGNED(4);
+ RadioCellIdentity_1_5 cellIdentity RADIO_ALIGNED(8);
+ GBinderHidlString registeredPlmn RADIO_ALIGNED(8);
+ guint8 accessTechnologySpecificInfoType RADIO_ALIGNED(1); /* RADIO_REG_ACCESS_TECHNOLOGY_SPECIFIC_INFO_TYPE */
+ union {
+ RadioRegCdma2000RegistrationInfo cdmaInfo RADIO_ALIGNED(4);
+ RadioRegEutranRegistrationInfo eutranInfo RADIO_ALIGNED(1);
+ } accessTechnologySpecificInfo RADIO_ALIGNED(4);
+} RADIO_ALIGNED(8) RadioRegStateResult_1_5; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioRegStateResult_1_5) == 224);
+
typedef struct radio_signal_strength_gsm {
guint32 signalStrength RADIO_ALIGNED(4);
guint32 bitErrorRate RADIO_ALIGNED(4);
@@ -1013,13 +2080,13 @@
typedef struct radio_cell_info_nr {
RadioSignalStrengthNr signalStrength RADIO_ALIGNED(4);
- RadioCellIdentityNr cellidentity RADIO_ALIGNED(8);
+ RadioCellIdentityNr cellIdentity RADIO_ALIGNED(8);
} RADIO_ALIGNED(8) RadioCellInfoNr; /* Since 1.2.5 */
G_STATIC_ASSERT(sizeof(RadioCellInfoNr) == 112);
typedef struct radio_cell_info_1_4 {
- guint32 registered RADIO_ALIGNED(1);
- guint32 connectionStatus RADIO_ALIGNED(4);
+ guint8 registered RADIO_ALIGNED(1);
+ RADIO_CELL_CONNECTION_STATUS connectionStatus RADIO_ALIGNED(4);
guint8 cellInfoType RADIO_ALIGNED(1); /* RADIO_CELL_INFO_TYPE_1_4 */
union {
RadioCellInfoGsm_1_2 gsm RADIO_ALIGNED(8);
@@ -1032,6 +2099,77 @@
} RADIO_ALIGNED(8) RadioCellInfo_1_4; /* Since 1.2.5 */
G_STATIC_ASSERT(sizeof(RadioCellInfo_1_4) == 136);
+typedef struct radio_cell_info_gsm_1_5 {
+ RadioCellIdentityGsm_1_5 cellIdentityGsm RADIO_ALIGNED(8);
+ RadioSignalStrengthGsm signalStrengthGsm RADIO_ALIGNED(4);
+} RADIO_ALIGNED(8) RadioCellInfoGsm_1_5; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioCellInfoGsm_1_5) == 112);
+
+typedef struct radio_cell_info_wcdma_1_5 {
+ RadioCellIdentityWcdma_1_5 cellIdentityWcdma RADIO_ALIGNED(8);
+ RadioSignalStrengthWcdma_1_2 signalStrengthWcdma RADIO_ALIGNED(4);
+} RADIO_ALIGNED(8) RadioCellInfoWcdma_1_5; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioCellInfoWcdma_1_5) == 152);
+
+typedef struct radio_cell_info_lte_1_5 {
+ RadioCellIdentityLte_1_5 cellIdentityLte RADIO_ALIGNED(8);
+ RadioSignalStrengthLte signalStrengthLte RADIO_ALIGNED(4);
+} RADIO_ALIGNED(8) RadioCellInfoLte_1_5; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioCellInfoLte_1_5) == 184);
+
+typedef struct radio_cell_info_tdscdma_1_5 {
+ RadioCellIdentityTdscdma_1_5 cellIdentityTdscdma RADIO_ALIGNED(8);
+ RadioSignalStrengthTdScdma_1_2 signalStrengthTdscdma RADIO_ALIGNED(4);
+} RADIO_ALIGNED(8) RadioCellInfoTdscdma_1_5; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioCellInfoTdscdma_1_5) == 160);
+
+typedef struct radio_cell_info_nr_1_5 {
+ RadioCellIdentityNr_1_5 cellIdentityNr RADIO_ALIGNED(8);
+ RadioSignalStrengthNr signalStrengthNr RADIO_ALIGNED(4);
+} RADIO_ALIGNED(8) RadioCellInfoNr_1_5; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioCellInfoNr_1_5) == 144);
+
+typedef struct radio_cell_info_1_5 {
+ guint8 registered RADIO_ALIGNED(1);
+ gint32 timeStampType RADIO_ALIGNED(4);
+ guint64 timeStamp RADIO_ALIGNED(8);
+ RADIO_CELL_CONNECTION_STATUS connectionStatus RADIO_ALIGNED(4);
+ guint8 cellInfoType RADIO_ALIGNED(8); /* RADIO_CELL_INFO_TYPE_1_5 */
+ union {
+ RadioCellInfoGsm_1_5 gsm RADIO_ALIGNED(8);
+ RadioCellInfoWcdma_1_5 wcdma RADIO_ALIGNED(8);
+ RadioCellInfoTdscdma_1_5 tdscdma RADIO_ALIGNED(8);
+ RadioCellInfoLte_1_5 lte RADIO_ALIGNED(8);
+ RadioCellInfoNr_1_5 nr RADIO_ALIGNED(8);
+ RadioCellInfoCdma_1_2 cdma RADIO_ALIGNED(8);
+ } info RADIO_ALIGNED(8);
+} RADIO_ALIGNED(8) RadioCellInfo_1_5; /* Since 1.5.0 */
+G_STATIC_ASSERT(sizeof(RadioCellInfo_1_5) == 216);
+
+typedef struct radio_physical_channel_config {
+ RADIO_CELL_CONNECTION_STATUS connectionStatus RADIO_ALIGNED(4);
+ gint32 cellBandwidthDownlink RADIO_ALIGNED(4);
+} RADIO_ALIGNED(4) RadioPhysicalChannelConfig; /* Since 1.5.4 */
+G_STATIC_ASSERT(sizeof(RadioPhysicalChannelConfig) == 8);
+
+typedef struct radio_frequency_info {
+ guint8 frequencyInfoType RADIO_ALIGNED(1); /* RADIO_FREQUENCY_INFO_TYPE */
+ union {
+ RADIO_FREQUENCY_RANGE range RADIO_ALIGNED(4);
+ gint32 channelNumber RADIO_ALIGNED(4);
+ } info RADIO_ALIGNED(4);
+} RADIO_ALIGNED(4) RadioFrequencyInfo; /* Since 1.5.4 */
+G_STATIC_ASSERT(sizeof(RadioFrequencyInfo) == 8);
+
+typedef struct radio_physical_channel_config_1_4 {
+ RadioPhysicalChannelConfig base RADIO_ALIGNED(4);
+ RADIO_TECH rat RADIO_ALIGNED(4);
+ RadioFrequencyInfo rfInfo RADIO_ALIGNED(4);
+ GBinderHidlVec contextIds RADIO_ALIGNED(8);
+ guint32 physicalCellId RADIO_ALIGNED(4);
+} RADIO_ALIGNED(8) RadioPhysicalChannelConfig_1_4; /* Since 1.5.4 */
+G_STATIC_ASSERT(sizeof(RadioPhysicalChannelConfig_1_4) == 48);
+
typedef struct radio_gsm_broadcast_sms_config {
gint32 fromServiceId RADIO_ALIGNED(4);
gint32 toServiceId RADIO_ALIGNED(4);
@@ -1045,7 +2183,7 @@
gint32 slot RADIO_ALIGNED(4);
gint32 appIndex RADIO_ALIGNED(4);
gint32 subType RADIO_ALIGNED(4);
- gint32 actStatus RADIO_ALIGNED(4);
+ RADIO_UICC_SUB_ACT actStatus RADIO_ALIGNED(4);
} RADIO_ALIGNED(4) RadioSelectUiccSub;
G_STATIC_ASSERT(sizeof(RadioSelectUiccSub) == 16);
@@ -1068,7 +2206,7 @@
typedef struct radio_capability {
gint32 session RADIO_ALIGNED(4);
RADIO_CAPABILITY_PHASE phase RADIO_ALIGNED(4);
- gint32 raf RADIO_ALIGNED(4);
+ RADIO_ACCESS_FAMILY raf RADIO_ALIGNED(4);
GBinderHidlString logicalModemUuid RADIO_ALIGNED(8);
RADIO_CAPABILITY_STATUS status RADIO_ALIGNED(4);
} RADIO_ALIGNED(8) RadioCapability;
@@ -1113,12 +2251,54 @@
typedef struct radio_network_scan_result {
RADIO_SCAN_STATUS status RADIO_ALIGNED(4);
- guint32 error RADIO_ALIGNED(4);
+ RADIO_ERROR error RADIO_ALIGNED(4);
GBinderHidlVec networkInfos RADIO_ALIGNED(8); /* vec<RadioCellInfo> */
+ /* or vec<RadioCellInfo_1_2> */
/* or vec<RadioCellInfo_1_4> */
+ /* or vec<RadioCellInfo_1_5> */
} RADIO_ALIGNED(8) RadioNetworkScanResult; /* Since 1.2.5 */
G_STATIC_ASSERT(sizeof(RadioNetworkScanResult) == 24);
+typedef struct radio_network_scan_specifier {
+ RADIO_ACCESS_NETWORKS radioAccessNetwork RADIO_ALIGNED(4);
+ GBinderHidlVec geranBands RADIO_ALIGNED(8); /* vec<RADIO_GERAN_BAND> */
+ GBinderHidlVec utranBands RADIO_ALIGNED(8); /* vec<RADIO_UTRAN_BAND> */
+ GBinderHidlVec eutranBands RADIO_ALIGNED(8); /* vec<RADIO_EUTRAN_BAND> */
+ GBinderHidlVec channels RADIO_ALIGNED(8); /* vec<int32_t> */
+} RADIO_ALIGNED(8) RadioAccessSpecifier; /* Since 1.5.2 */
+G_STATIC_ASSERT(sizeof(RadioAccessSpecifier) == 72);
+
+typedef struct radio_network_scan_specifier_1_5 {
+ RADIO_ACCESS_NETWORKS radioAccessNetwork RADIO_ALIGNED(4);
+ guint8 type RADIO_ALIGNED(8); /* RADIO_NETWORK_SCAN_SPECIFIER_1_5_TYPE */
+ GBinderHidlVec bands RADIO_ALIGNED(8); /* vec<RADIO_GERAN_BAND> */
+ /* or vec<RADIO_UTRAN_BAND> */
+ /* or vec<RADIO_EUTRAN_BAND> */
+ /* or vec<RADIO_NGRAN_BAND> */
+ GBinderHidlVec channels RADIO_ALIGNED(8); /* vec<int32_t> */
+} RADIO_ALIGNED(8) RadioAccessSpecifier_1_5; /* Since 1.5.2 */
+G_STATIC_ASSERT(sizeof(RadioAccessSpecifier_1_5) == 48);
+
+typedef struct radio_network_scan_request {
+ RADIO_SCAN_TYPE type RADIO_ALIGNED(4);
+ gint32 interval RADIO_ALIGNED(4); /* Periodic scan interval, seconds */
+ GBinderHidlVec specifiers RADIO_ALIGNED(8); /* vec<RadioAccessSpecifier> */
+} RADIO_ALIGNED(8) RadioNetworkScanRequest; /* Since 1.5.2 */
+G_STATIC_ASSERT(sizeof(RadioNetworkScanRequest) == 24);
+
+typedef struct radio_network_scan_request_1_5 {
+ RADIO_SCAN_TYPE type RADIO_ALIGNED(4);
+ gint32 interval RADIO_ALIGNED(4); /* [5..300] seconds */
+ GBinderHidlVec specifiers RADIO_ALIGNED(8); /*vec <RadioAccessSpecifier> */
+ /*or vec<RadioAccessSpecifier_1_5> */
+ gint32 maxSearchTime RADIO_ALIGNED(4); /* [60..3600] seconds */
+ guint8 incrementalResults RADIO_ALIGNED(1); /* TRUE/FALSE */
+ gint32 incrementalResultsPeriodicity RADIO_ALIGNED(4); /* [1..10] */
+ GBinderHidlVec mccMncs RADIO_ALIGNED(8); /* vec<GBinderHidlString> */
+} RADIO_ALIGNED(8) RadioNetworkScanRequest_1_2,
+ RadioNetworkScanRequest_1_5; /* Since 1.5.2 */
+G_STATIC_ASSERT(sizeof(RadioNetworkScanRequest_1_5) == 56);
+
/* c(req,resp,callName,CALL_NAME) */
#define RADIO_CALL_1_0(c) \
c(2,1,getIccCardStatus,GET_ICC_CARD_STATUS) \
@@ -1267,14 +2447,43 @@
c(144,145,enableModem,ENABLE_MODEM) \
c(145,146,getModemStackStatus,GET_MODEM_STACK_STATUS)
-#define RADIO_CALL_1_4(c) /* Since 1.2.5 */ \
- c(149,147,emergencyDial,EMERGENCY_DIAL) \
- c(150,148,startNetworkScan_1_4,START_NETWORKSCAN_1_4) \
- c(151,152,getPreferredNetworkTypeBitmap,GET_PREFERRED_NETWORK_TYPE_BITMAP) \
- c(152,153,setPreferredNetworkTypeBitmap,SET_PREFERRED_NETWORK_TYPE_BITMAP) \
- c(153,156,setAllowedCarriers_1_4,SET_ALLOWED_CARRIERS_1_4) \
- c(154,157,getAllowedCarriers_1_4,GET_ALLOWED_CARRIERS_1_4) \
- c(155,158,getSignalStrength_1_4,GET_SIGNAL_STRENGTH_1_4)
+/*
+ * From 1.2.5 to 1.5.0 there was RADIO_CALL_1_4 which took a macro with 4
+ * arguments as a parameter. In 1.5.1 it was replaced with RADIO_CALL_1_4_
+ * which takes a macro with 5 arguments.
+ */
+#define RADIO_CALL_1_4_(c) /* Since 1.5.1 */ \
+ c(146,155,setupDataCall,SETUP_DATA_CALL,_1_4) \
+ c(149,147,emergencyDial,EMERGENCY_DIAL,) \
+ c(150,148,startNetworkScan,START_NETWORK_SCAN,_1_4) \
+ c(151,152,getPreferredNetworkTypeBitmap,GET_PREFERRED_NETWORK_TYPE_BITMAP,) \
+ c(152,153,setPreferredNetworkTypeBitmap,SET_PREFERRED_NETWORK_TYPE_BITMAP,) \
+ c(153,156,setAllowedCarriers,SET_ALLOWED_CARRIERS,_1_4) \
+ c(154,157,getAllowedCarriers,GET_ALLOWED_CARRIERS,_1_4) \
+ c(155,158,getSignalStrength,GET_SIGNAL_STRENGTH,_1_4)
+
+/*
+ * Similarly to RADIO_CALL_1_4, RADIO_CALL_1_5 macro which appeared in 1.5.0
+ * was replaced with RADIO_CALL_1_5_ in 1.5.1
+ */
+#define RADIO_CALL_1_5_(c) /* Since 1.5.1 */ \
+ c(156,159,setSignalStrengthReportingCriteria,SET_SIGNAL_STRENGTH_REPORTING_CRITERIA,_1_5) \
+ c(157,160,setLinkCapacityReportingCriteria,SET_LINK_CAPACITY_REPORTING_CRITERIA,_1_5) \
+ c(158,161,enableUiccApplications,ENABLE_UICC_APPLICATIONS,) \
+ c(159,162,areUiccApplicationsEnabled,ARE_UICC_APPLICATIONS_ENABLED,) \
+ c(160,163,setSystemSelectionChannels,SET_SYSTEM_SELECTION_CHANNELS,_1_5) \
+ c(161,164,startNetworkScan,START_NETWORK_SCAN,_1_5) \
+ c(162,165,setupDataCall,SETUP_DATA_CALL,_1_5) \
+ c(163,167,setInitialAttachApn,SET_INITIAL_ATTACH_APN,_1_5) \
+ c(164,168,setDataProfile,SET_DATA_PROFILE,_1_5) \
+ c(165,169,setRadioPower,SET_RADIO_POWER,_1_5) \
+ c(166,170,setIndicationFilter,SET_INDICATION_FILTER,_1_5) \
+ c(167,171,getBarringInfo,GET_BARRING_INFO,) \
+ c(168,172,getVoiceRegistrationState,GET_VOICE_REGISTRATION_STATE,_1_5) \
+ c(169,173,getDataRegistrationState,GET_DATA_REGISTRATION_STATE,_1_5) \
+ c(170,175,setNetworkSelectionModeManual,SET_NETWORK_SELECTION_MODE_MANUAL,_1_5) \
+ c(171,176,sendCdmaSmsExpectMore,SEND_CDMA_SMS_EXPECT_MORE,) \
+ c(172,177,supplySimDepersonalization,SUPPLY_SIM_PERSONALIZATION,)
/* e(code,eventName,EVENT_NAME) */
#define RADIO_EVENT_1_0(e) \
@@ -1344,10 +2553,19 @@
e(58,dataCallListChanged_1_4,DATA_CALL_LIST_CHANGED_1_4) \
e(59,currentSignalStrength_1_4,CURRENT_SIGNAL_STRENGTH_1_4)
+#define RADIO_EVENT_1_5(e) /* Since 1.5.0 */ \
+ e(60,uiccApplicationsEnablementChanged, UICC_APPLICATION_ENABLEMENT_CHANGED) \
+ e(61,registrationFailed, REGISTRATION_FAILED) \
+ e(62,barringInfoChanged, BARRING_INFO_CHANGED) \
+ e(63,cellInfoList_1_5,CELL_INFO_LIST_1_5) \
+ e(64,networkScanResult_1_5,NETWORK_SCAN_RESULT_1_5) \
+ e(65,dataCallListChanged_1_5,DATA_CALL_LIST_CHANGED_1_5)
+
typedef enum radio_req {
RADIO_REQ_ANY = 0,
RADIO_REQ_NONE = 0,
#define RADIO_REQ_(req,resp,Name,NAME) RADIO_REQ_##NAME = req,
+#define RADIO_REQ__(req,resp,Name,NAME,x) RADIO_REQ_##NAME##x = req,
/* android.hardware.radio@1.0::IRadio */
RADIO_REQ_SET_RESPONSE_FUNCTIONS = 1, /* setResponseFunctions */
@@ -1372,18 +2590,24 @@
RADIO_1_3_REQ_LAST = RADIO_REQ_GET_MODEM_STACK_STATUS,
/* android.hardware.radio@1.4::IRadio */
- RADIO_CALL_1_4(RADIO_REQ_) /* Since 1.2.5 */
- RADIO_REQ_SETUP_DATA_CALL_1_4 = 146,
+ RADIO_CALL_1_4_(RADIO_REQ__) /* Since 1.2.5 */
RADIO_REQ_SET_INITIAL_ATTACH_APN_1_4 = 147,
RADIO_REQ_SET_DATA_PROFILE_1_4 = 148,
- RADIO_1_4_REQ_LAST = RADIO_REQ_GET_SIGNAL_STRENGTH_1_4
+ RADIO_1_4_REQ_LAST = RADIO_REQ_GET_SIGNAL_STRENGTH_1_4,
+
+ /* android.hardware.radio@1.5::IRadio */
+ RADIO_CALL_1_5_(RADIO_REQ__) /* Since 1.5.0 */
+ RADIO_1_5_REQ_LAST = RADIO_REQ_SUPPLY_SIM_PERSONALIZATION
#undef RADIO_REQ_
+#undef RADIO_REQ__
} RADIO_REQ;
+G_STATIC_ASSERT(sizeof(RADIO_REQ) == 4);
typedef enum radio_resp {
RADIO_RESP_ANY = 0,
RADIO_RESP_NONE = 0,
#define RADIO_RESP_(req,resp,Name,NAME) RADIO_RESP_##NAME = resp,
+#define RADIO_RESP__(req,resp,Name,NAME,x) RADIO_RESP_##NAME##x = resp,
/* android.hardware.radio@1.0::IRadioResponse */
RADIO_CALL_1_0(RADIO_RESP_)
@@ -1409,15 +2633,39 @@
RADIO_1_3_RESP_LAST = RADIO_RESP_GET_MODEM_STACK_STATUS,
/* android.hardware.radio@1.4::IRadioResponse */
- RADIO_CALL_1_4(RADIO_RESP_) /* Since 1.2.5 */
- RADIO_RESP_GET_CELL_INFO_LIST_RESPONSE_1_4 = 149,
- RADIO_RESP_GET_DATA_REGISTRATION_STATE_RESPONSE_1_4 = 150,
- RADIO_RESP_GET_ICC_CARD_STATUS_RESPONSE_1_4 = 151,
- RADIO_RESP_GET_DATA_CALL_LIST_RESPONSE_1_4 = 154,
- RADIO_RESP_SETUP_DATA_CALL_RESPONSE_1_4 = 155,
- RADIO_1_4_RESP_LAST = RADIO_RESP_GET_SIGNAL_STRENGTH_1_4
+ RADIO_CALL_1_4_(RADIO_RESP__) /* Since 1.2.5 */
+ RADIO_RESP_GET_CELL_INFO_LIST_1_4 = 149,
+ RADIO_RESP_GET_DATA_REGISTRATION_STATE_1_4 = 150,
+ RADIO_RESP_GET_ICC_CARD_STATUS_1_4 = 151,
+ RADIO_RESP_GET_DATA_CALL_LIST_1_4 = 154,
+ RADIO_1_4_RESP_LAST = RADIO_RESP_GET_SIGNAL_STRENGTH_1_4,
+
+ /* android.hardware.radio@1.5::IRadioResponse */
+ RADIO_CALL_1_5_(RADIO_RESP__) /* Since 1.5.0 */
+ RADIO_RESP_GET_DATA_CALL_LIST_1_5 = 166,
+ RADIO_RESP_GET_CELL_INFO_LIST_1_5 = 174,
+ RADIO_RESP_GET_ICC_CARD_STATUS_1_5 = 178,
+ RADIO_1_5_RESP_LAST = RADIO_RESP_GET_ICC_CARD_STATUS_1_5
#undef RADIO_RESP_
+#undef RADIO_RESP__
} RADIO_RESP;
+G_STATIC_ASSERT(sizeof(RADIO_RESP) == 4);
+
+/* These identifiers were shortened in 1.4.3 */
+#define RADIO_RESP_GET_CELL_INFO_LIST_RESPONSE_1_4 \
+ RADIO_RESP_GET_CELL_INFO_LIST_1_4
+#define RADIO_RESP_GET_DATA_REGISTRATION_STATE_RESPONSE_1_4 \
+ RADIO_RESP_GET_DATA_REGISTRATION_STATE_1_4
+#define RADIO_RESP_GET_ICC_CARD_STATUS_RESPONSE_1_4 \
+ RADIO_RESP_GET_ICC_CARD_STATUS_1_4
+#define RADIO_RESP_GET_DATA_CALL_LIST_RESPONSE_1_4 \
+ RADIO_RESP_GET_DATA_CALL_LIST_1_4
+#define RADIO_RESP_SETUP_DATA_CALL_RESPONSE_1_4 \
+ RADIO_RESP_SETUP_DATA_CALL_1_4
+
+/* These were renamed in 1.4.5 for consistency */
+#define RADIO_REQ_START_NETWORKSCAN_1_4 RADIO_REQ_START_NETWORK_SCAN_1_4
+#define RADIO_RESP_START_NETWORKSCAN_1_4 RADIO_RESP_START_NETWORK_SCAN_1_4
typedef enum radio_ind {
RADIO_IND_ANY = 0,
@@ -1441,9 +2689,18 @@
/* android.hardware.radio@1.4::IRadioIndication */
RADIO_EVENT_1_4(RADIO_IND_)
- RADIO_1_4_IND_LAST = RADIO_IND_CURRENT_SIGNAL_STRENGTH_1_4 /* Since 1.2.5 */
+ RADIO_1_4_IND_LAST = RADIO_IND_CURRENT_SIGNAL_STRENGTH_1_4, /* Since 1.2.5 */
+
+ /* android.hardware.radio@1.5::IRadioIndication */
+ RADIO_EVENT_1_5(RADIO_IND_)
+ RADIO_1_5_IND_LAST = RADIO_IND_DATA_CALL_LIST_CHANGED_1_5 /* Since 1.5.0 */
#undef RADIO_IND_
} RADIO_IND;
+G_STATIC_ASSERT(sizeof(RADIO_IND) == 4);
+
+/* Legacy macro. Ignore it */
+
+#define DATA_CALL_VERSION (11)
/* Logging */
@@ -1462,4 +2719,3 @@
* indent-tabs-mode: nil
* End:
*/
-
|
[-]
[+]
|
Changed |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/include/radio_util.h
^
|
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2018-2019 Jolla Ltd.
- * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
+ * Copyright (C) 2018-2021 Jolla Ltd.
+ * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
@@ -55,7 +55,13 @@
RADIO_RESP
radio_req_resp(
- RADIO_REQ req);
+ RADIO_REQ req)
+ G_GNUC_DEPRECATED_FOR(radio_req_resp2);
+
+RADIO_RESP
+radio_req_resp2(
+ RADIO_REQ req,
+ RADIO_INTERFACE iface); /* Since 1.4.5 */
G_END_DECLS
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/src/radio_base.c
^
|
@@ -0,0 +1,1014 @@
+/*
+ * Copyright (C) 2021-2022 Jolla Ltd.
+ * Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include "radio_base.h"
+#include "radio_request_p.h"
+#include "radio_util.h"
+#include "radio_log.h"
+
+/*
+ * Requests are considered pending for no longer than pending_timeout
+ * because pending requests prevent blocking requests from being
+ * submitted and we don't want to get stuck forever.
+ */
+#define DEFAULT_PENDING_TIMEOUT_MS (30000)
+
+#define KEY(serial) GUINT_TO_POINTER(serial)
+
+struct radio_base_priv {
+ GHashTable* requests; /* All requests (weak references) */
+ GHashTable* active; /* Requests in QUEUED and PENDING states */
+ GHashTable* pending; /* Requests in PENDING state */
+ RadioRequest* queue_first; /* First QUEUED request */
+ RadioRequest* queue_last; /* Last QUEUED request */
+ RadioRequest* block_req;
+ RadioRequestGroup* owner;
+ GSList* owner_queue;
+
+ gint64 next_wakeup; /* When the next timer is scheduled */
+ guint default_timeout_ms; /* Default PENDING timeout, milliseconds */
+ guint timeout_id;
+};
+
+#define PARENT_CLASS radio_base_parent_class
+#define THIS_TYPE RADIO_TYPE_BASE
+#define THIS(obj) RADIO_BASE(obj)
+G_DEFINE_ABSTRACT_TYPE(RadioBase, radio_base, G_TYPE_OBJECT)
+
+enum radio_base_signal {
+ SIGNAL_OWNER,
+ SIGNAL_COUNT
+};
+
+#define SIGNAL_OWNER_NAME "radio-base-owner"
+
+static guint radio_base_signals[SIGNAL_COUNT] = { 0 };
+
+static inline gboolean
+radio_base_can_retry(RadioRequest* req)
+ { return req->max_retries < 0 || req->max_retries > req->retry_count; }
+
+/*==========================================================================*
+ * Implementation
+ *==========================================================================*/
+
+static
+guint32
+radio_base_reserve_serial(
+ RadioBase* self)
+{
+ /*
+ * Using a static counter practically guarantees that different
+ * serials would never be in use simultanously by different
+ * RadioBase-derived objects. And hopefully reduce the chance
+ * of confusion on the service side.
+ */
+ static guint32 last_serial = 0;
+ RadioBasePriv* priv = self->priv;
+
+ do { last_serial++; }
+ while (!last_serial ||
+ g_hash_table_contains(priv->requests, KEY(last_serial)));
+ return last_serial;
+}
+
+static
+void
+radio_base_unlink_request(
+ RadioBasePriv* q,
+ RadioRequest* req,
+ RadioRequest* prev)
+{
+ RadioRequest* next = req->queue_next;
+
+ if (prev) {
+ prev->queue_next = next;
+ } else {
+ q->queue_first = next;
+ }
+ if (next) {
+ req->queue_next = NULL;
+ } else {
+ q->queue_last = prev;
+ }
+}
+
+static
+gboolean
+radio_base_dequeue_request(
+ RadioBasePriv* q,
+ RadioRequest* req)
+{
+ RadioRequest* ptr = q->queue_first;
+ RadioRequest* prev = NULL;
+
+ while (ptr) {
+ if (ptr == req) {
+ radio_base_unlink_request(q, req, prev);
+ return TRUE;
+ }
+ prev = ptr;
+ ptr = ptr->queue_next;
+ }
+ return FALSE;
+}
+
+static
+void
+radio_base_deactivate_request(
+ RadioBase* self,
+ RadioRequest* req)
+{
+ RadioBasePriv* priv = self->priv;
+
+ g_hash_table_remove(priv->pending, KEY(req->serial2));
+ g_hash_table_remove(priv->pending, KEY(req->serial));
+ g_hash_table_remove(priv->active, KEY(req->serial2));
+ g_hash_table_remove(priv->active, KEY(req->serial));
+ if (req->state == RADIO_REQUEST_STATE_QUEUED) {
+ radio_base_dequeue_request(priv, req);
+ }
+ if (priv->block_req == req) {
+ /* Let the life continue */
+ priv->block_req = NULL;
+ GVERBOSE_("block %p => %p", req, priv->block_req);
+ radio_request_unref(req);
+ }
+}
+
+static
+void
+radio_base_drop_req(
+ RadioBase* self,
+ RadioRequest* req)
+{
+ radio_base_cancel_request(self, req);
+ radio_base_deactivate_request(self, req);
+ radio_base_reset_timeout(self);
+ if (req->state < RADIO_REQUEST_STATE_FAILED) {
+ req->state = RADIO_REQUEST_STATE_CANCELLED;
+ }
+}
+
+static
+void
+radio_base_detach_req(
+ gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ RadioRequest* req = value;
+
+ radio_base_cancel_request(THIS(user_data), req);
+ req->object = NULL;
+}
+
+static
+void
+radio_base_fail_request(
+ RadioBase* self,
+ RadioRequest* req,
+ RADIO_REQUEST_STATE state,
+ RADIO_TX_STATUS status)
+{
+ radio_request_ref(req);
+ req->state = state;
+ if (req->complete) {
+ RadioRequestCompleteFunc complete = req->complete;
+
+ req->complete = NULL;
+ complete(req, status, RADIO_RESP_NONE, RADIO_ERROR_NONE, NULL,
+ req->user_data);
+ }
+ radio_base_drop_req(self, req);
+ radio_request_unref(req);
+}
+
+static
+void
+radio_base_request_failed(
+ RadioBase* self,
+ RadioRequest* req)
+{
+ radio_base_fail_request(self, req,
+ RADIO_REQUEST_STATE_FAILED,
+ RADIO_TX_STATUS_FAILED);
+}
+
+static
+void
+radio_base_request_sent(
+ RadioBase* self,
+ RadioRequest* req,
+ int status)
+{
+ req->tx_id = 0;
+ if (status != GBINDER_STATUS_OK) {
+ g_object_ref(self);
+ radio_base_request_failed(self, req);
+ g_object_unref(self);
+ }
+}
+
+static
+gboolean
+radio_base_submit_transaction(
+ RadioBase* self,
+ RadioRequest* req)
+{
+ RadioBasePriv* priv = self->priv;
+
+ if (req->serial2) {
+ const guint32 used = req->serial2;
+
+ /* Pick another serial and record it */
+ req->serial2 = radio_base_reserve_serial(self);
+ g_hash_table_insert(priv->requests, KEY(req->serial2), req);
+ g_hash_table_insert(priv->active, KEY(req->serial2),
+ radio_request_ref(req));
+
+ /* Drop the old one */
+ g_hash_table_remove(priv->pending, KEY(used));
+ g_hash_table_remove(priv->active, KEY(used));
+
+ /* Keep the original serial in priv->requests */
+ if (used != req->serial) {
+ g_hash_table_remove(priv->requests, KEY(used));
+ }
+
+ /* Update the RPC header */
+ radio_request_update_serial(req, req->serial2);
+ GDEBUG("Resubmitting request %u [%08x => %08x]",
+ req->code, used, req->serial2);
+ } else {
+ /* First submission */
+ req->serial2 = req->serial;
+ }
+
+ /* Actually submit the transaction */
+ req->tx_id = RADIO_BASE_GET_CLASS(self)->send_request(self, req,
+ radio_base_request_sent);
+ if (req->tx_id) {
+ req->scheduled = 0; /* Not scheduled anymore */
+ req->state = RADIO_REQUEST_STATE_PENDING;
+ g_hash_table_insert(priv->pending, KEY(req->serial2),
+ radio_request_ref(req));
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+static
+gboolean
+radio_base_can_set_owner(
+ RadioBasePriv* priv,
+ RadioRequestGroup* group)
+{
+ /*
+ * Caller has verified that the group isn't already the owner.
+ * It's also been checked that either the owner queue is empty,
+ * of this group is the first one in the queue.
+ */
+ DEBUG_ASSERT(!priv->owner_queue || priv->owner_queue->data == group);
+
+ if (g_hash_table_size(priv->pending)) {
+ GHashTableIter it;
+ gpointer value;
+
+ g_hash_table_iter_init(&it, priv->pending);
+ while (g_hash_table_iter_next(&it, NULL, &value)) {
+ RadioRequest* req = value;
+
+ DEBUG_ASSERT(req->state == RADIO_REQUEST_STATE_PENDING);
+ if (req->group != group) {
+ /*
+ * There's a pending request not associated with any
+ * group or associated with a different group. The
+ * specified group can't become the owner just yet.
+ */
+ return FALSE;
+ }
+ }
+
+ }
+
+ /*
+ * There are no pending requests, or all pending requests are
+ * associated with this group.
+ */
+ return TRUE;
+}
+
+static
+void
+radio_base_move_owner_queue(
+ RadioBase* self)
+{
+ RadioBasePriv* priv = self->priv;
+
+ if (!priv->owner && priv->owner_queue) {
+ GSList* l = priv->owner_queue;
+ RadioRequestGroup* group = l->data;
+
+ if (radio_base_can_set_owner(priv, group)) {
+ GVERBOSE_("owner %p", group);
+ priv->owner = group;
+ priv->owner_queue = l->next;
+ g_slist_free_1(l);
+ g_signal_emit(self, radio_base_signals[SIGNAL_OWNER], 0);
+ }
+ }
+}
+
+static
+gboolean
+radio_base_can_submit_request(
+ RadioBasePriv* priv,
+ RadioRequest* req)
+{
+ if (priv->block_req) {
+ /* The current blocker can be resubmitted */
+ return priv->block_req == req;
+ } else if (req->group) {
+ /* The request is a part of a group */
+ if (req->group == priv->owner) {
+ /* The group is the current owner */
+ return TRUE;
+ } else if (priv->owner) {
+ /* Another group owns the whole thing */
+ return FALSE;
+ } else if (!priv->owner_queue) {
+ /* No group is waiting to become the owner */
+ return TRUE;
+ } else if (priv->owner_queue->data == req->group) {
+ /*
+ * This group is waiting to become the owner and it's the
+ * first one in the queue.
+ */
+ return radio_base_can_set_owner(priv, req->group);
+ } else {
+ /*
+ * Another group waiting to become the owner. This request
+ * will have to wait.
+ */
+ return FALSE;
+ }
+ } else {
+ /* Can submit if there's no owner and no one wants to become one */
+ return !priv->owner && !priv->owner_queue;
+ }
+}
+
+static
+void
+radio_base_queue_request(
+ RadioBasePriv* priv,
+ RadioRequest* req)
+{
+ req->state = RADIO_REQUEST_STATE_QUEUED;
+ if (priv->queue_last) {
+ priv->queue_last->queue_next = req;
+ } else {
+ priv->queue_first = req;
+ }
+ priv->queue_last = req;
+}
+
+static
+guint
+radio_base_submit_queued_requests(
+ RadioBase* self)
+{
+ RadioBasePriv* priv = self->priv;
+ guint submitted = 0;
+
+ if (RADIO_BASE_GET_CLASS(self)->can_submit_requests(self)) {
+ RadioRequest* prev = NULL;
+ RadioRequest* req = priv->queue_first;
+ const gint64 now = g_get_monotonic_time();
+
+ while (req) {
+ RadioRequest* next = req->queue_next;
+
+ if (radio_base_can_submit_request(priv, req) &&
+ /* If the request is scheduled, don't submit it too early */
+ (!req->scheduled || now >= req->scheduled)) {
+ /* Remove it from the queue (prev remains untouched) */
+ radio_base_unlink_request(priv, req, prev);
+
+ /* Initiate the transaction and update the request state */
+ if (radio_base_submit_transaction(self, req)) {
+ radio_base_move_owner_queue(self);
+ submitted++;
+ if (req->blocking) {
+ if (!priv->block_req) {
+ GVERBOSE_("block %p => %p", priv->block_req, req);
+ priv->block_req = radio_request_ref(req);
+ }
+ break;
+ }
+ } else {
+ radio_base_request_failed(self, req);
+ }
+ } else {
+ /* What hasn't been removed from the queue, becomes prev */
+ prev = req;
+ }
+ req = next;
+ }
+ }
+ return submitted;
+}
+
+static
+gboolean
+radio_base_timeout(
+ gpointer user_data)
+{
+ RadioBase* self = THIS(user_data);
+ RadioBasePriv* priv = self->priv;
+ const gint64 now = g_get_monotonic_time();
+ GHashTableIter it;
+ gpointer value;
+ GSList* expired = NULL;
+ RadioRequest* req;
+
+ g_object_ref(self);
+ priv->timeout_id = 0;
+
+ /* Scan all active requests (including the queued ones) */
+ g_hash_table_iter_init(&it, priv->active);
+ while (g_hash_table_iter_next(&it, NULL, &value)) {
+ req = value;
+ if (req->deadline <= now) {
+ GDEBUG("Request %u (%08x/%08x) expired",
+ req->code, req->serial, req->serial2);
+
+ /* Don't unref those just yet */
+ g_hash_table_iter_steal(&it);
+ expired = g_slist_append(expired, req);
+ }
+ }
+
+ if (expired) {
+ GSList* l;
+
+ /*
+ * We are still holding the stolen reference for each expired request,
+ * meaning this won't destroy them and won't invoke any callbacks.
+ */
+ for (l = expired; l; l = l->next) {
+ radio_base_deactivate_request(self, l->data);
+ }
+
+ /*
+ * And this loop may and probably will invoke callbacks and may
+ * even drop the last references to the requests.
+ */
+ for (l = expired; l; l = l->next) {
+ req = l->data;
+ radio_base_fail_request(self, req,
+ RADIO_REQUEST_STATE_FAILED,
+ RADIO_TX_STATUS_TIMEOUT);
+ /* Drop the stolen reference */
+ radio_request_unref(req);
+ }
+
+ /* Done with the list */
+ g_slist_free(expired);
+ }
+
+ /* A retry timeout may have expired, check if we need to submit requests */
+ radio_base_submit_queued_requests(self);
+ radio_base_reset_timeout(self);
+ g_object_unref(self);
+ return G_SOURCE_REMOVE;
+}
+
+/*==========================================================================*
+ * Internal API
+ *==========================================================================*/
+
+void
+radio_base_initialize(
+ RadioBase* self)
+{
+}
+
+void
+radio_base_register_request(
+ RadioBase* self,
+ RadioRequest* req)
+{
+ /* Caller makes sure that both arguments are not NULL */
+ RadioBasePriv* priv = self->priv;
+
+ req->object = self;
+ req->serial = radio_base_reserve_serial(self);
+ g_hash_table_insert(priv->requests, KEY(req->serial), req);
+}
+
+void
+radio_base_unregister_request(
+ RadioBase* self,
+ RadioRequest* req)
+{
+ /* Caller doesn't check base for NULL */
+ if (G_LIKELY(self)) {
+ RadioBasePriv* priv = self->priv;
+
+ GVERBOSE_("request %u %p (%08x) done", req->code, req, req->serial);
+ g_hash_table_remove(priv->requests, KEY(req->serial));
+ g_hash_table_remove(priv->requests, KEY(req->serial2));
+ req->serial = req->serial2 = 0;
+ req->object = NULL;
+ }
+}
+
+gboolean
+radio_base_submit_request(
+ RadioBase* self,
+ RadioRequest* req)
+{
+ /*
+ * Caller makes sure that both arguments are not NULL. Note that if the
+ * base is dead, request stays in the NEW state and can be resubmitted
+ * later (not sure if this is a useful feature though).
+ */
+ if (req->state == RADIO_REQUEST_STATE_NEW &&
+ !RADIO_BASE_GET_CLASS(self)->is_dead(self)) {
+ RadioBasePriv* priv = self->priv;
+ RadioRequestCompleteFunc complete = req->complete;
+ const guint timeout = radio_base_timeout_ms(self, req);
+
+ /* Queue the request */
+ req->deadline = g_get_monotonic_time() + MICROSEC(timeout);
+ radio_base_queue_request(priv, req);
+
+ /* Create an internal reference to the request */
+ g_hash_table_insert(priv->active, KEY(req->serial),
+ radio_request_ref(req));
+
+ /* Don't complete the request if it fails right away */
+ req->complete = NULL;
+ if (radio_base_submit_queued_requests(self)) {
+ radio_base_reset_timeout(self);
+ }
+ if (req->state < RADIO_REQUEST_STATE_FAILED) {
+ req->complete = complete;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+gboolean
+radio_base_retry_request(
+ RadioBase* self,
+ RadioRequest* req)
+{
+ /* Caller makes sure that both arguments are not NULL */
+ if (req->state == RADIO_REQUEST_STATE_PENDING &&
+ radio_base_can_retry(req)) {
+ RadioBasePriv* priv = self->priv;
+
+ radio_base_cancel_request(self, req);
+ req->retry_count++;
+ radio_base_queue_request(priv, req);
+ if (radio_base_submit_queued_requests(self)) {
+ radio_base_reset_timeout(self);
+ }
+ if (req->state == RADIO_REQUEST_STATE_PENDING) {
+ return TRUE;
+ }
+ }
+ GVERBOSE_("can't retry request %u (%08x/%08x) %p", req->code,
+ req->serial, req->serial2, req);
+ return FALSE;
+}
+
+void
+radio_base_request_dropped(
+ RadioRequest* req)
+{
+ if (req->object) {
+ radio_base_drop_req(req->object, req);
+ }
+}
+
+guint
+radio_base_timeout_ms(
+ RadioBase* self,
+ RadioRequest* req)
+{
+ /* Caller checks object pointer for NULL */
+ return req->timeout_ms ? req->timeout_ms : self->priv->default_timeout_ms;
+}
+
+void
+radio_base_reset_timeout(
+ RadioBase* self)
+{
+ RadioBasePriv* priv = self->priv;
+
+ if (g_hash_table_size(priv->active)) {
+ GHashTableIter it;
+ const gint64 now = g_get_monotonic_time();
+ gint64 next_wakeup = 0;
+ gpointer value;
+
+ /* Calculate the new deadline */
+ GVERBOSE_("time %" G_GINT64_FORMAT " block %p owner %p queue %p",
+ now, priv->block_req, priv->owner, priv->owner_queue ?
+ priv->owner_queue->data : NULL);
+
+ g_hash_table_iter_init(&it, priv->active);
+ while (g_hash_table_iter_next(&it, NULL, &value)) {
+ RadioRequest* req = value;
+
+ GVERBOSE_("%p %" G_GINT64_FORMAT " %" G_GINT64_FORMAT, req,
+ req->deadline, req->scheduled);
+ if (!next_wakeup || next_wakeup > req->deadline) {
+ GVERBOSE_(" %" G_GINT64_FORMAT " => %" G_GINT64_FORMAT,
+ next_wakeup, req->deadline);
+ next_wakeup = req->deadline;
+ }
+ if (req->scheduled && radio_base_can_submit_request(priv, req)) {
+ if (!next_wakeup || next_wakeup > req->scheduled) {
+ GVERBOSE_(" %" G_GINT64_FORMAT " => %" G_GINT64_FORMAT,
+ next_wakeup, req->scheduled);
+ next_wakeup = req->scheduled;
+ }
+ }
+ }
+
+ if (next_wakeup) {
+ /* Convert to milliseconds */
+ const guint timeout_ms = (next_wakeup > now) ?
+ (guint)(((next_wakeup - now) + 999)/1000) : 0;
+
+ /* Start or restart the timer (should it be suspend-aware?) */
+ if (priv->timeout_id) {
+ g_source_remove(priv->timeout_id);
+ }
+ GVERBOSE("Next timeout check in %u ms", timeout_ms);
+ priv->next_wakeup = next_wakeup;
+ priv->timeout_id = timeout_ms ?
+ g_timeout_add(timeout_ms, radio_base_timeout, self) :
+ g_idle_add(radio_base_timeout, self);
+ }
+ } else {
+ /* No more pending requests, cancel the timeout */
+ if (priv->timeout_id) {
+ g_source_remove(priv->timeout_id);
+ priv->timeout_id = 0;
+ }
+ }
+}
+
+RADIO_BLOCK
+radio_base_block_status(
+ RadioBase* self,
+ RadioRequestGroup* group)
+{
+ RadioBasePriv* priv = self->priv;
+
+ /* Caller checks object pointer for NULL */
+ if (priv->owner == group) {
+ return RADIO_BLOCK_ACQUIRED;
+ } else if (g_slist_find(priv->owner_queue, group)) {
+ return RADIO_BLOCK_QUEUED;
+ } else {
+ return RADIO_BLOCK_NONE;
+ }
+}
+
+RADIO_BLOCK
+radio_base_block(
+ RadioBase* self,
+ RadioRequestGroup* group)
+{
+ RadioBasePriv* priv = self->priv;
+
+ /* Caller checks object pointer for NULL */
+ if (priv->owner == group) {
+ /* This group is already the owner */
+ return RADIO_BLOCK_ACQUIRED;
+ } else if (!priv->owner && !priv->owner_queue &&
+ radio_base_can_set_owner(priv, group)) {
+ GVERBOSE_("owner %p", group);
+ priv->owner = group;
+ g_signal_emit(self, radio_base_signals[SIGNAL_OWNER], 0);
+ return RADIO_BLOCK_ACQUIRED;
+ } else {
+ if (!g_slist_find(priv->owner_queue, group)) {
+ /* Not found in the queue */
+ priv->owner_queue = g_slist_append(priv->owner_queue, group);
+ }
+ return RADIO_BLOCK_QUEUED;
+ }
+}
+
+void
+radio_base_unblock(
+ RadioBase* self,
+ RadioRequestGroup* group)
+{
+ /* Parameters are checked by the caller */
+ RadioBasePriv* priv = self->priv;
+
+ if (priv->owner == group) {
+ if (priv->owner_queue) {
+ priv->owner = priv->owner_queue->data;
+ priv->owner_queue = g_slist_delete_link(priv->owner_queue,
+ priv->owner_queue);
+ } else {
+ GVERBOSE_("owner %p", NULL);
+ priv->owner = NULL;
+ }
+ g_signal_emit(self, radio_base_signals[SIGNAL_OWNER], 0);
+ if (radio_base_submit_queued_requests(self) || !priv->owner) {
+ radio_base_reset_timeout(self);
+ }
+ } else {
+ priv->owner_queue = g_slist_remove(priv->owner_queue, group);
+ }
+}
+
+gboolean
+radio_base_handle_resp(
+ RadioBase* self,
+ guint32 code,
+ const RadioResponseInfo* info,
+ const GBinderReader* reader)
+{
+ RadioBasePriv* priv = self->priv;
+ RadioRequest* req = g_hash_table_lookup(priv->active, KEY(info->serial));
+
+ if (req) {
+ RadioRequestRetryFunc retry = req->retry;
+
+ /* Temporary ref */
+ g_object_ref(self);
+
+ /* It's no longer pending */
+ g_hash_table_remove(priv->pending, KEY(info->serial));
+
+ /* Response may come before completion of the request */
+ radio_base_cancel_request(self, req);
+
+ /* Do we need to retry? */
+ if (radio_base_can_retry(req) && retry(req, RADIO_TX_STATUS_OK,
+ code, info->error, reader, req->user_data)) {
+ /* Re-queue the request */
+ req->retry_count++;
+ req->scheduled = g_get_monotonic_time() +
+ MICROSEC(req->retry_delay_ms);
+ radio_base_queue_request(priv, req);
+ } else if (g_hash_table_steal(priv->active, KEY(info->serial))) {
+ req->state = RADIO_REQUEST_STATE_DONE;
+ radio_base_deactivate_request(self, req);
+ radio_base_move_owner_queue(self);
+ if (req->complete) {
+ RadioRequestCompleteFunc fn = req->complete;
+
+ req->complete = NULL;
+ fn(req, RADIO_TX_STATUS_OK, code, info->error, reader,
+ req->user_data);
+ }
+ radio_request_unref(req);
+ }
+
+ radio_base_submit_queued_requests(self);
+ radio_base_reset_timeout(self);
+ g_object_unref(self);
+ return TRUE;
+ }
+ /* Most likely, the corresponding request was cancelled */
+ return FALSE;
+}
+
+void
+radio_base_handle_ack(
+ RadioBase* self,
+ guint32 serial)
+{
+ RadioBasePriv* priv = self->priv;
+ RadioRequest* req = g_hash_table_lookup(priv->active, KEY(serial));
+
+ if (req) {
+ GDEBUG("%08x acked", serial);
+ req->acked = TRUE;
+ } else {
+ GWARN("%08x unexpected ack", serial);
+ }
+}
+
+void
+radio_base_handle_death(
+ RadioBase* self)
+{
+ RadioBasePriv* priv = self->priv;
+ RadioRequest* dead = NULL;
+ RadioRequest* req;
+ GHashTableIter it;
+ gpointer value;
+
+ /*
+ * We are going to empty the queue and reuse queue_next link to
+ * build the list of dead requests.
+ */
+ priv->queue_first = priv->queue_last = NULL;
+
+ /* Steal all active requests from the table */
+ g_hash_table_remove_all(priv->pending);
+ g_hash_table_iter_init(&it, priv->active);
+ while (g_hash_table_iter_next(&it, NULL, &value)) {
+ req = value;
+ GDEBUG("Dropping request %u (%08x/%08x) due to radio death",
+ req->code, req->serial, req->serial2);
+
+ /* Don't unref them just yet */
+ g_hash_table_iter_steal(&it);
+
+ /*
+ * Make sure that request state isn't RADIO_REQUEST_STATE_QUEUED,
+ * so that we can safely reuse queue_next link.
+ */
+ req->state = RADIO_REQUEST_STATE_QUEUED;
+ req->queue_next = dead;
+ dead = req;
+ }
+
+ while (dead) {
+ /* Fail the dead request and drop the stolen ref */
+ req = dead;
+ dead = req->queue_next;
+ req->queue_next = NULL;
+ radio_base_request_failed(self, req);
+ radio_request_unref(req);
+ }
+}
+
+void
+radio_base_submit_requests(
+ RadioBase* self)
+{
+ if (radio_base_submit_queued_requests(self)) {
+ radio_base_reset_timeout(self);
+ }
+}
+
+void
+radio_base_cancel_request(
+ RadioBase* self,
+ RadioRequest* req)
+{
+ req->scheduled = 0;
+ if (req->tx_id) {
+ RADIO_BASE_GET_CLASS(self)->cancel_request(self, req->tx_id);
+ req->tx_id = 0;
+ }
+}
+
+void
+radio_base_set_default_timeout(
+ RadioBase* self,
+ int ms)
+{
+ /* Caller checks object pointer for NULL */
+ RadioBasePriv* priv = self->priv;
+
+ if (ms <= 0) {
+ ms = DEFAULT_PENDING_TIMEOUT_MS;
+ }
+ if (priv->default_timeout_ms != ms) {
+ const int delta = ms - priv->default_timeout_ms;
+ gboolean updated = FALSE;
+ GHashTableIter it;
+ gpointer value;
+
+ /* Calculate new deadlines */
+ g_hash_table_iter_init(&it, priv->active);
+ while (g_hash_table_iter_next(&it, NULL, &value)) {
+ RadioRequest* req = value;
+
+ if (!req->timeout_ms) {
+ /* This request is using the default timeout */
+ req->deadline += MICROSEC(delta);
+ updated = TRUE;
+ }
+ }
+ priv->default_timeout_ms = ms;
+ if (updated) {
+ radio_base_reset_timeout(self);
+ }
+ }
+}
+
+gulong
+radio_base_add_owner_changed_handler(
+ RadioBase* self,
+ RadioBaseFunc fn,
+ gpointer user_data)
+{
+ /* Caller checks object pointer for NULL */
+ return G_LIKELY(fn) ?
+ g_signal_connect_closure_by_id(self, radio_base_signals[SIGNAL_OWNER],
+ 0, g_cclosure_new(G_CALLBACK(fn), user_data, NULL), FALSE) : 0;
+}
+
+/*==========================================================================*
+ * Internals
+ *==========================================================================*/
+
+static
+void
+radio_base_init(
+ RadioBase* self)
+{
+ RadioBasePriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self, RADIO_TYPE_BASE,
+ RadioBasePriv);
+
+ self->priv = priv;
+ priv->requests = g_hash_table_new(g_direct_hash, g_direct_equal);
+ priv->active = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, radio_request_unref_func);
+ priv->pending = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, radio_request_unref_func);
+ priv->default_timeout_ms = DEFAULT_PENDING_TIMEOUT_MS;
+}
+
+static
+void
+radio_base_object_finalize(
+ GObject* object)
+{
+ RadioBase* self = THIS(object);
+ RadioBasePriv* priv = self->priv;
+
+ if (priv->timeout_id) {
+ g_source_remove(priv->timeout_id);
+ }
+ g_hash_table_foreach(priv->requests, radio_base_detach_req, self);
+ g_hash_table_destroy(priv->requests);
+ g_hash_table_destroy(priv->active);
+ g_hash_table_destroy(priv->pending);
+ G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
+}
+
+static
+void
+radio_base_class_init(
+ RadioBaseClass* klass)
+{
+ g_type_class_add_private(klass, sizeof(RadioBasePriv));
+ G_OBJECT_CLASS(klass)->finalize = radio_base_object_finalize;
+ radio_base_signals[SIGNAL_OWNER] = g_signal_new(SIGNAL_OWNER_NAME,
+ G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/src/radio_base.h
^
|
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2021-2022 Jolla Ltd.
+ * Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#ifndef RADIO_BASE_H
+#define RADIO_BASE_H
+
+#include "radio_types_p.h"
+
+#include <glib-object.h>
+
+/* RadioBaseFunc must be compatible with RadioClientFunc */
+typedef
+void
+(*RadioBaseFunc)(
+ RadioBase* base,
+ gpointer user_data);
+
+typedef
+void
+(*RadioBaseRequestSentFunc)(
+ RadioBase* base,
+ RadioRequest* req,
+ int status);
+
+typedef struct radio_base_priv RadioBasePriv;
+
+struct radio_base {
+ GObject object;
+ RadioBasePriv* priv;
+};
+
+typedef struct radio_base_class {
+ GObjectClass parent;
+ gboolean (*is_dead)(RadioBase* base);
+ gboolean (*can_submit_requests)(RadioBase* base);
+ GBinderLocalRequest* (*new_request)(RadioBase* base, guint32 code);
+ gulong (*send_request)(RadioBase* base, RadioRequest* req,
+ RadioBaseRequestSentFunc sent);
+ void (*cancel_request)(RadioBase* base, gulong id);
+} RadioBaseClass;
+
+GType radio_base_get_type(void) RADIO_INTERNAL;
+#define RADIO_TYPE_BASE radio_base_get_type()
+#define RADIO_BASE(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ RADIO_TYPE_BASE, RadioBase)
+#define RADIO_BASE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), \
+ RADIO_TYPE_BASE, RadioBaseClass)
+#define RADIO_BASE_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), \
+ THIS_TYPE, RadioBaseClass)
+
+void
+radio_base_initialize(
+ RadioBase* base)
+ RADIO_INTERNAL;
+
+void
+radio_base_register_request(
+ RadioBase* base,
+ RadioRequest* req)
+ RADIO_INTERNAL;
+
+void
+radio_base_unregister_request(
+ RadioBase* base,
+ RadioRequest* req)
+ RADIO_INTERNAL;
+
+gboolean
+radio_base_submit_request(
+ RadioBase* base,
+ RadioRequest* req)
+ RADIO_INTERNAL;
+
+gboolean
+radio_base_retry_request(
+ RadioBase* base,
+ RadioRequest* req)
+ RADIO_INTERNAL;
+
+void
+radio_base_request_dropped(
+ RadioRequest* req)
+ RADIO_INTERNAL;
+
+guint
+radio_base_timeout_ms(
+ RadioBase* base,
+ RadioRequest* req)
+ RADIO_INTERNAL;
+
+void
+radio_base_reset_timeout(
+ RadioBase* base)
+ RADIO_INTERNAL;
+
+RADIO_BLOCK
+radio_base_block_status(
+ RadioBase* base,
+ RadioRequestGroup* group)
+ RADIO_INTERNAL;
+
+RADIO_BLOCK
+radio_base_block(
+ RadioBase* base,
+ RadioRequestGroup* group)
+ RADIO_INTERNAL;
+
+void
+radio_base_unblock(
+ RadioBase* base,
+ RadioRequestGroup* group)
+ RADIO_INTERNAL;
+
+gboolean
+radio_base_handle_resp(
+ RadioBase* base,
+ guint32 code,
+ const RadioResponseInfo* info,
+ const GBinderReader* reader)
+ RADIO_INTERNAL;
+
+void
+radio_base_handle_ack(
+ RadioBase* base,
+ guint32 serial)
+ RADIO_INTERNAL;
+
+void
+radio_base_handle_death(
+ RadioBase* base)
+ RADIO_INTERNAL;
+
+void
+radio_base_submit_requests(
+ RadioBase* base)
+ RADIO_INTERNAL;
+
+void
+radio_base_cancel_request(
+ RadioBase* base,
+ RadioRequest* req)
+ RADIO_INTERNAL;
+
+void
+radio_base_set_default_timeout(
+ RadioBase* self,
+ int ms)
+ RADIO_INTERNAL;
+
+gulong
+radio_base_add_owner_changed_handler(
+ RadioBase* base,
+ RadioBaseFunc func,
+ gpointer user_data)
+ RADIO_INTERNAL;
+
+#endif /* RADIO_BASE_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/src/radio_client.c
^
|
@@ -0,0 +1,473 @@
+/*
+ * Copyright (C) 2021-2022 Jolla Ltd.
+ * Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#include "radio_base.h"
+#include "radio_client.h"
+#include "radio_instance_p.h"
+#include "radio_request_p.h"
+#include "radio_util.h"
+#include "radio_log.h"
+
+#include <gutil_macros.h>
+#include <gutil_misc.h>
+
+/* This API exists since 1.4.3 */
+
+enum radio_events {
+ RADIO_EVENT_IND,
+ RADIO_EVENT_RESP,
+ RADIO_EVENT_ACK,
+ RADIO_EVENT_DEATH,
+ RADIO_EVENT_CONNECTED,
+ RADIO_EVENT_COUNT
+};
+
+struct radio_client {
+ RadioBase base;
+ RadioInstance* instance;
+ gulong event_ids[RADIO_EVENT_COUNT];
+};
+
+typedef RadioBaseClass RadioClientClass;
+GType radio_client_get_type() RADIO_INTERNAL;
+G_DEFINE_TYPE(RadioClient, radio_client, RADIO_TYPE_BASE)
+
+#define PARENT_CLASS radio_client_parent_class
+#define THIS_TYPE radio_client_get_type()
+#define THIS(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, THIS_TYPE, RadioClient)
+
+typedef struct radio_client_call {
+ RadioRequest* req;
+ RadioBaseRequestSentFunc callback;
+} RadioClientCall;
+
+enum radio_client_signal {
+ SIGNAL_INDICATION,
+ SIGNAL_DEATH,
+ SIGNAL_CONNECTED,
+ SIGNAL_COUNT
+};
+
+#define SIGNAL_INDICATION_NAME "radio-client-indication"
+#define SIGNAL_DEATH_NAME "radio-client-death"
+#define SIGNAL_CONNECTED_NAME "radio-client-connected"
+
+static guint radio_client_signals[SIGNAL_COUNT] = { 0 };
+
+/*==========================================================================*
+ * Implementation
+ *==========================================================================*/
+
+static
+void
+radio_client_call_free(
+ RadioClientCall* call)
+{
+ radio_request_unref(call->req);
+ gutil_slice_free(call);
+}
+
+static
+void
+radio_client_call_destroy(
+ void* user_data1,
+ void* user_data2)
+{
+ radio_client_call_free(user_data2);
+}
+
+static
+void
+radio_client_call_complete(
+ RadioInstance* instance,
+ gulong id,
+ int status,
+ void* user_data1,
+ void* user_data2)
+{
+ RadioClientCall* call = user_data2;
+
+ call->callback(RADIO_BASE(user_data1), call->req, status);
+}
+
+static
+void
+radio_client_handle_death(
+ RadioInstance* instance,
+ gpointer user_data)
+{
+ RadioBase* base = RADIO_BASE(user_data);
+
+ g_object_ref(base);
+ radio_base_handle_death(base);
+ g_signal_emit(base, radio_client_signals[SIGNAL_DEATH], 0);
+ g_object_unref(base);
+}
+
+static
+void
+radio_client_handle_connected(
+ RadioInstance* instance,
+ gpointer user_data)
+{
+ g_signal_emit(THIS(user_data), radio_client_signals[SIGNAL_CONNECTED], 0);
+ radio_base_submit_requests(RADIO_BASE(user_data));
+}
+
+static
+void
+radio_client_handle_ack(
+ RadioInstance* instance,
+ guint32 serial,
+ gpointer user_data)
+{
+ radio_base_handle_ack(RADIO_BASE(user_data), serial);
+}
+
+static
+void
+radio_client_handle_ind(
+ RadioInstance* instance,
+ RADIO_IND code,
+ RADIO_IND_TYPE type,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ g_signal_emit(THIS(user_data), radio_client_signals[SIGNAL_INDICATION],
+ radio_instance_ind_quark(instance, code), code, reader);
+}
+
+static
+void
+radio_client_handle_resp(
+ RadioInstance* instance,
+ RADIO_RESP code,
+ const RadioResponseInfo* info,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ if (!radio_base_handle_resp(RADIO_BASE(user_data), code, info, reader)) {
+ const char* name = radio_resp_name(code);
+
+ /* Most likely this is a response to a cancelled request */
+ GDEBUG("Ignoring IRadio response [%08x] %u %s", info->serial, code,
+ name ? name : "");
+ }
+}
+
+static
+gulong
+radio_client_add_handler(
+ RadioClient* self,
+ enum radio_client_signal sig,
+ RadioClientFunc fn,
+ gpointer user_data)
+{
+ return (G_LIKELY(self) && G_LIKELY(fn)) ?
+ g_signal_connect_closure_by_id(self, radio_client_signals[sig], 0,
+ g_cclosure_new(G_CALLBACK(fn), user_data, NULL), FALSE) : 0;
+}
+
+/*==========================================================================*
+ * API
+ *==========================================================================*/
+
+RadioClient*
+radio_client_new(
+ RadioInstance* instance)
+{
+ RadioClient* self = NULL;
+
+ if (G_LIKELY(instance)) {
+ self = g_object_new(THIS_TYPE, NULL);
+ radio_base_initialize(&self->base);
+ self->instance = radio_instance_ref(instance);
+ self->event_ids[RADIO_EVENT_IND] =
+ radio_instance_add_indication_observer(instance, RADIO_IND_ANY,
+ radio_client_handle_ind, self);
+ self->event_ids[RADIO_EVENT_RESP] =
+ radio_instance_add_response_observer(instance, RADIO_RESP_ANY,
+ radio_client_handle_resp, self);
+ self->event_ids[RADIO_EVENT_ACK] =
+ radio_instance_add_ack_handler(instance,
+ radio_client_handle_ack, self);
+ self->event_ids[RADIO_EVENT_DEATH] =
+ radio_instance_add_death_handler(instance,
+ radio_client_handle_death, self);
+ self->event_ids[RADIO_EVENT_CONNECTED] =
+ radio_instance_add_connected_handler(instance,
+ radio_client_handle_connected, self);
+ }
+ return self;
+}
+
+RadioClient*
+radio_client_ref(
+ RadioClient* self)
+{
+ if (G_LIKELY(self)) {
+ g_object_ref(self);
+ }
+ return self;
+}
+
+void
+radio_client_unref(
+ RadioClient* self)
+{
+ if (G_LIKELY(self)) {
+ g_object_unref(self);
+ }
+}
+
+const char*
+radio_client_slot(
+ RadioClient* self)
+{
+ return G_LIKELY(self) ? self->instance->slot : NULL;
+}
+
+gboolean
+radio_client_dead(
+ RadioClient* self)
+{
+ return !self || self->instance->dead;
+}
+
+gboolean
+radio_client_connected(
+ RadioClient* self)
+{
+ return self && self->instance->connected;
+}
+
+RADIO_INTERFACE
+radio_client_interface(
+ RadioClient* self)
+{
+ return G_LIKELY(self) ? self->instance->version : RADIO_INTERFACE_NONE;
+}
+
+void
+radio_client_set_default_timeout(
+ RadioClient* self,
+ int milliseconds)
+{
+ if (G_LIKELY(self)) {
+ radio_base_set_default_timeout(&self->base, milliseconds);
+ }
+}
+
+gulong
+radio_client_add_indication_handler(
+ RadioClient* self,
+ RADIO_IND code,
+ RadioClientIndicationFunc fn,
+ gpointer user_data)
+{
+ return (G_LIKELY(self) && G_LIKELY(fn)) ?
+ g_signal_connect_closure_by_id(self,
+ radio_client_signals[SIGNAL_INDICATION],
+ radio_instance_ind_quark(self->instance, code),
+ g_cclosure_new(G_CALLBACK(fn), user_data, NULL), FALSE) : 0;
+}
+
+gulong
+radio_client_add_owner_changed_handler(
+ RadioClient* self,
+ RadioClientFunc fn,
+ gpointer user_data)
+{
+ return self ? radio_base_add_owner_changed_handler(&self->base,
+ (RadioBaseFunc) fn, user_data) : 0;
+}
+
+gulong
+radio_client_add_death_handler(
+ RadioClient* self,
+ RadioClientFunc fn,
+ gpointer user_data)
+{
+ return radio_client_add_handler(self, SIGNAL_DEATH, fn, user_data);
+}
+
+gulong
+radio_client_add_connected_handler(
+ RadioClient* self,
+ RadioClientFunc fn,
+ gpointer user_data)
+{
+ return radio_client_add_handler(self, SIGNAL_CONNECTED, fn, user_data);
+}
+
+void
+radio_client_remove_handler(
+ RadioClient* self,
+ gulong id)
+{
+ if (G_LIKELY(id) && G_LIKELY(self)) {
+ g_signal_handler_disconnect(self, id);
+ }
+}
+
+void
+radio_client_remove_handlers(
+ RadioClient* self,
+ gulong* ids,
+ int count)
+{
+ gutil_disconnect_handlers(self, ids, count);
+}
+
+/*==========================================================================*
+ * Methods
+ *==========================================================================*/
+
+static
+gboolean
+radio_client_is_dead(
+ RadioBase* base)
+{
+ return THIS(base)->instance->dead;
+}
+
+static
+gboolean
+radio_client_can_submit_requests(
+ RadioBase* base)
+{
+ return THIS(base)->instance->connected;
+}
+
+static
+GBinderLocalRequest*
+radio_client_new_request(
+ RadioBase* base,
+ guint32 code)
+{
+ return radio_instance_new_request(THIS(base)->instance, code);
+}
+
+static
+gulong
+radio_client_send_request(
+ RadioBase* base,
+ RadioRequest* req,
+ RadioBaseRequestSentFunc callback)
+{
+ RadioClientCall* call = g_slice_new(RadioClientCall);
+ gulong tx_id;
+
+ call->callback = callback;
+ call->req = radio_request_ref(req);
+ tx_id = radio_instance_send_request(THIS(base)->instance,
+ req->code, req->args, radio_client_call_complete,
+ radio_client_call_destroy, base, call);
+ if (tx_id) {
+ return tx_id;
+ } else {
+ radio_client_call_free(call);
+ return 0;
+ }
+}
+
+static
+void
+radio_client_cancel_request(
+ RadioBase* base,
+ gulong id)
+{
+ radio_instance_cancel_request(THIS(base)->instance, id);
+}
+
+/*==========================================================================*
+ * Internals
+ *==========================================================================*/
+
+static
+void
+radio_client_init(
+ RadioClient* self)
+{
+}
+
+static
+void
+radio_client_finalize(
+ GObject* object)
+{
+ RadioClient* self = THIS(object);
+
+ radio_instance_remove_all_handlers(self->instance, self->event_ids);
+ radio_instance_unref(self->instance);
+ G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
+}
+
+static
+void
+radio_client_class_init(
+ RadioClientClass* klass)
+{
+ RadioBaseClass* base_class = RADIO_BASE_CLASS(klass);
+ GObjectClass* object_class = G_OBJECT_CLASS(klass);
+ GType type = G_OBJECT_CLASS_TYPE(klass);
+
+ base_class->is_dead = radio_client_is_dead;
+ base_class->can_submit_requests = radio_client_can_submit_requests;
+ base_class->new_request = radio_client_new_request;
+ base_class->send_request = radio_client_send_request;
+ base_class->cancel_request = radio_client_cancel_request;
+ object_class->finalize = radio_client_finalize;
+
+ radio_client_signals[SIGNAL_INDICATION] =
+ g_signal_new(SIGNAL_INDICATION_NAME, type,
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED, 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_POINTER);
+ radio_client_signals[SIGNAL_DEATH] =
+ g_signal_new(SIGNAL_DEATH_NAME, type, G_SIGNAL_RUN_FIRST, 0,
+ NULL, NULL, NULL, G_TYPE_NONE, 0);
+ radio_client_signals[SIGNAL_CONNECTED] =
+ g_signal_new(SIGNAL_CONNECTED_NAME, type, G_SIGNAL_RUN_FIRST, 0,
+ NULL, NULL, NULL, G_TYPE_NONE, 0);
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/src/radio_config.c
^
|
@@ -0,0 +1,1008 @@
+/*
+ * Copyright (C) 2022 Jolla Ltd.
+ * Copyright (C) 2022 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#include "radio_base.h"
+#include "radio_config.h"
+#include "radio_log.h"
+#include "radio_request_p.h"
+#include "radio_util_p.h"
+
+#include <gbinder.h>
+
+#include <gutil_idlepool.h>
+#include <gutil_macros.h>
+#include <gutil_misc.h>
+#include <gutil_strv.h>
+
+/* This API exists since 1.4.6 */
+
+typedef struct radio_config {
+ RadioBase base;
+ GUtilIdlePool* pool;
+ GBinderClient* client;
+ GBinderRemoteObject* remote;
+ GBinderLocalObject* response;
+ GBinderLocalObject* indication;
+ RADIO_CONFIG_INTERFACE version;
+ GHashTable* req_quarks;
+ GHashTable* resp_quarks;
+ GHashTable* ind_quarks;
+ gulong death_id;
+ gboolean dead;
+} RadioConfig;
+
+typedef RadioBaseClass RadioConfigClass;
+GType radio_config_get_type() RADIO_INTERNAL;
+G_DEFINE_TYPE(RadioConfig, radio_config, RADIO_TYPE_BASE)
+
+#define PARENT_CLASS radio_config_parent_class
+#define THIS_TYPE radio_config_get_type()
+#define THIS(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, THIS_TYPE, RadioConfig)
+
+typedef enum radio_config_signal {
+ #define SIGNAL_INDEX(x) SIGNAL_OBSERVE_REQUEST_##x,
+ FOREACH_OBSERVER_PRIORITY(SIGNAL_INDEX)
+ #undef SIGNAL_INDEX
+ #define SIGNAL_INDEX(x) SIGNAL_OBSERVE_RESPONSE_##x,
+ FOREACH_OBSERVER_PRIORITY(SIGNAL_INDEX)
+ #undef SIGNAL_INDEX
+ #define SIGNAL_INDEX(x) SIGNAL_OBSERVE_INDICATION_##x,
+ FOREACH_OBSERVER_PRIORITY(SIGNAL_INDEX)
+ #undef SIGNAL_INDEX
+ SIGNAL_INDICATION,
+ SIGNAL_DEATH,
+ SIGNAL_COUNT
+} RADIO_CONFIG_SIGNAL;
+
+static const char* radio_config_signal_observe_request_name[] = {
+ #define SIGNAL_NAME(x) "radio-config-observe-request-" #x,
+ FOREACH_OBSERVER_PRIORITY(SIGNAL_NAME)
+ #undef SIGNAL_NAME
+ NULL
+};
+
+static const char* radio_config_signal_observe_response_name[] = {
+ #define SIGNAL_NAME(x) "radio-config-observe-response-" #x,
+ FOREACH_OBSERVER_PRIORITY(SIGNAL_NAME)
+ #undef SIGNAL_NAME
+ NULL
+};
+
+static const char* radio_config_signal_observe_indication_name[] = {
+ #define SIGNAL_NAME(x) "radio-config-observe-indication-" #x,
+ FOREACH_OBSERVER_PRIORITY(SIGNAL_NAME)
+ #undef SIGNAL_NAME
+ NULL
+};
+
+#define SIGNAL_INDICATION_NAME "radio-config-indication"
+#define SIGNAL_DEATH_NAME "radio-config-death"
+
+static guint radio_config_signals[SIGNAL_COUNT] = { 0 };
+
+static const GBinderClientIfaceInfo radio_config_iface_info[] = {
+ {RADIO_CONFIG_1_1, RADIO_CONFIG_1_1_REQ_LAST },
+ {RADIO_CONFIG_1_1, RADIO_CONFIG_1_1_REQ_LAST },
+ {RADIO_CONFIG_1_0, RADIO_CONFIG_1_0_REQ_LAST }
+};
+G_STATIC_ASSERT(G_N_ELEMENTS(radio_config_iface_info) ==
+ RADIO_CONFIG_INTERFACE_COUNT);
+
+static const char* const radio_config_indication_ifaces[] = {
+ RADIO_CONFIG_INDICATION_1_2,
+ RADIO_CONFIG_INDICATION_1_1,
+ RADIO_CONFIG_INDICATION_1_0,
+ NULL
+};
+G_STATIC_ASSERT(G_N_ELEMENTS(radio_config_indication_ifaces) ==
+ RADIO_CONFIG_INTERFACE_COUNT + 1);
+
+static const char* const radio_config_response_ifaces[] = {
+ RADIO_CONFIG_RESPONSE_1_2,
+ RADIO_CONFIG_RESPONSE_1_1,
+ RADIO_CONFIG_RESPONSE_1_0,
+ NULL
+};
+G_STATIC_ASSERT(G_N_ELEMENTS(radio_config_response_ifaces) ==
+ RADIO_CONFIG_INTERFACE_COUNT + 1);
+
+typedef struct radio_config_interface_desc {
+ RADIO_CONFIG_INTERFACE version;
+ const char* fqname;
+ const char* radio_iface;
+ const char* const* ind_ifaces;
+ const char* const* resp_ifaces;
+} RadioConfigInterfaceDesc;
+
+#define RADIO_CONFIG_INTERFACE_INDEX(x) (RADIO_CONFIG_INTERFACE_COUNT - x - 1)
+
+#define RADIO_CONFIG_INTERFACE_DESC(v) \
+ RADIO_CONFIG_INTERFACE_##v, \
+ RADIO_CONFIG_##v##_FQNAME, \
+ RADIO_CONFIG_##v, \
+ radio_config_indication_ifaces + \
+ RADIO_CONFIG_INTERFACE_INDEX(RADIO_CONFIG_INTERFACE_##v), \
+ radio_config_response_ifaces + \
+ RADIO_CONFIG_INTERFACE_INDEX(RADIO_CONFIG_INTERFACE_##v)
+
+static const RadioConfigInterfaceDesc radio_config_interfaces[] = {
+ { RADIO_CONFIG_INTERFACE_DESC(1_2) },
+ { RADIO_CONFIG_INTERFACE_DESC(1_1) },
+ { RADIO_CONFIG_INTERFACE_DESC(1_0) }
+};
+G_STATIC_ASSERT(G_N_ELEMENTS(radio_config_interfaces) ==
+ RADIO_CONFIG_INTERFACE_COUNT);
+
+/* Must have a separate instance for each interface version */
+static RadioConfig* radio_config_instance[RADIO_CONFIG_INTERFACE_COUNT] =
+ { NULL };
+
+typedef struct radio_config_call {
+ RadioRequest* req;
+ RadioBaseRequestSentFunc callback;
+ RadioBase* object;
+} RadioConfigCall;
+
+/*==========================================================================*
+ * Implementation
+ *==========================================================================*/
+
+static
+void
+radio_config_call_free(
+ RadioConfigCall* call)
+{
+ radio_request_unref(call->req);
+ gutil_slice_free(call);
+}
+
+static
+void
+radio_config_call_complete(
+ GBinderClient* client,
+ GBinderRemoteReply* reply,
+ int status,
+ void* user_data)
+{
+ RadioConfigCall* call = user_data;
+
+ call->callback(call->object, call->req, status);
+}
+
+static
+const char*
+radio_config_known_req_name(
+ RADIO_CONFIG_REQ req)
+{
+ switch (req) {
+ case RADIO_CONFIG_REQ_SET_RESPONSE_FUNCTIONS: return "setResponseFunctions";
+#define RADIO_CONFIG_REQ_(req,resp,Name,NAME) \
+ case RADIO_CONFIG_REQ_##NAME: return #Name;
+ RADIO_CONFIG_CALL_1_0(RADIO_CONFIG_REQ_)
+ RADIO_CONFIG_CALL_1_1(RADIO_CONFIG_REQ_)
+ /* 1.2 defines no new requests */
+#undef RADIO_CONFIG_REQ_
+ case RADIO_CONFIG_REQ_ANY:
+ break;
+ }
+ return NULL;
+}
+
+static
+const char*
+radio_config_known_resp_name(
+ RADIO_CONFIG_RESP resp)
+{
+ switch (resp) {
+#define RADIO_CONFIG_RESP_(req,resp,Name,NAME) \
+ case RADIO_CONFIG_RESP_##NAME: return #Name "Response";
+ RADIO_CONFIG_CALL_1_0(RADIO_CONFIG_RESP_)
+ RADIO_CONFIG_CALL_1_1(RADIO_CONFIG_RESP_)
+#undef RADIO_CONFIG_RESP_
+ case RADIO_CONFIG_RESP_GET_SIM_SLOTS_STATUS_1_2:
+ return "getSimSlotsStatusResponse_1_2";
+ case RADIO_CONFIG_RESP_ANY:
+ break;
+ }
+ return NULL;
+}
+
+static
+const char*
+radio_config_known_ind_name(
+ RADIO_CONFIG_IND ind)
+{
+ switch (ind) {
+#define RADIO_CONFIG_IND_(code,Name,NAME) \
+ case RADIO_CONFIG_IND_##NAME: return #Name;
+ RADIO_CONFIG_IND_1_0(RADIO_CONFIG_IND_)
+ /* 1.1 defines no new indications */
+ RADIO_CONFIG_IND_1_2(RADIO_CONFIG_IND_)
+#undef RADIO_CONFIG_IND_
+ case RADIO_CONFIG_IND_ANY:
+ break;
+ }
+ return NULL;
+}
+
+static
+GQuark
+radio_config_req_quark(
+ RadioConfig* self,
+ RADIO_CONFIG_REQ req)
+{
+ GQuark q = 0;
+
+ if (req != RADIO_CONFIG_REQ_ANY) {
+ gpointer key = GUINT_TO_POINTER(req);
+
+ q = GPOINTER_TO_UINT(g_hash_table_lookup(self->req_quarks, key));
+ if (!q) {
+ const char* known = radio_config_known_req_name(req);
+
+ if (known) {
+ q = g_quark_from_static_string(known);
+ } else {
+ q = g_quark_from_string(radio_config_req_name(self, req));
+ }
+ g_hash_table_insert(self->req_quarks, key, GUINT_TO_POINTER(q));
+ }
+ }
+ return q;
+}
+
+static
+GQuark
+radio_config_resp_quark(
+ RadioConfig* self,
+ RADIO_CONFIG_RESP resp)
+{
+ GQuark q = 0;
+
+ if (resp != RADIO_CONFIG_RESP_ANY) {
+ gpointer key = GUINT_TO_POINTER(resp);
+
+ q = GPOINTER_TO_UINT(g_hash_table_lookup(self->resp_quarks, key));
+ if (!q) {
+ const char* known = radio_config_known_resp_name(resp);
+
+ if (known) {
+ q = g_quark_from_static_string(known);
+ } else {
+ q = g_quark_from_string(radio_config_resp_name(self, resp));
+ }
+ g_hash_table_insert(self->resp_quarks, key, GUINT_TO_POINTER(q));
+ }
+ }
+ return q;
+}
+
+static
+GQuark
+radio_config_ind_quark(
+ RadioConfig* self,
+ RADIO_CONFIG_IND ind)
+{
+ GQuark q = 0;
+
+ if (ind != RADIO_CONFIG_IND_ANY) {
+ gpointer key = GUINT_TO_POINTER(ind);
+
+ q = GPOINTER_TO_UINT(g_hash_table_lookup(self->ind_quarks, key));
+ if (!q) {
+ const char* known = radio_config_known_ind_name(ind);
+
+ if (known) {
+ q = g_quark_from_static_string(known);
+ } else {
+ q = g_quark_from_string(radio_config_ind_name(self, ind));
+ }
+ g_hash_table_insert(self->ind_quarks, key, GUINT_TO_POINTER(q));
+ }
+ }
+ return q;
+}
+
+static
+GBinderLocalReply*
+radio_config_indication(
+ GBinderLocalObject* obj,
+ GBinderRemoteRequest* req,
+ guint code,
+ guint flags,
+ int* status,
+ void* user_data)
+{
+ RadioConfig* self = THIS(user_data);
+ const char* iface = gbinder_remote_request_interface(req);
+
+ if (gutil_strv_contains((GStrV*)radio_config_indication_ifaces, iface)) {
+ GBinderReader args;
+ guint type;
+
+ /*
+ * All these should be one-way and have RADIO_IND_UNSOLICITED type
+ * as the first parameter. RADIO_IND_ACK_EXP is not expected because
+ * IRadioConfig doesn't have responseAcknowledgement
+ */
+ GASSERT(flags & GBINDER_TX_FLAG_ONEWAY);
+ gbinder_remote_request_init_reader(req, &args);
+ if (gbinder_reader_read_uint32(&args, &type) &&
+ type == RADIO_IND_UNSOLICITED) {
+ int i;
+ const GQuark quark = radio_config_ind_quark(self, code);
+ const guint* signals = radio_config_signals +
+ SIGNAL_OBSERVE_INDICATION_0;
+
+ for (i = RADIO_OBSERVER_PRIORITY_COUNT - 1; i >=0; i--) {
+ if (signals[i]) {
+ g_signal_emit(self, signals[i], quark, code, &args);
+ }
+ }
+ *status = GBINDER_STATUS_OK;
+ } else {
+ GWARN("Failed to decode IRadioConfig indication %u", code);
+ *status = GBINDER_STATUS_FAILED;
+ }
+ }
+ return NULL;
+}
+
+static
+GBinderLocalReply*
+radio_config_response(
+ GBinderLocalObject* obj,
+ GBinderRemoteRequest* req,
+ guint code,
+ guint flags,
+ int* status,
+ void* user_data)
+{
+ RadioConfig* self = THIS(user_data);
+ const char* iface = gbinder_remote_request_interface(req);
+
+ if (gutil_strv_contains((GStrV*)radio_config_response_ifaces, iface)) {
+ GBinderReader args;
+ const RadioResponseInfo* info;
+
+ /* All responses must be one-way and have RadioResponseInfo */
+ gbinder_remote_request_init_reader(req, &args);
+ info = gbinder_reader_read_hidl_struct(&args, RadioResponseInfo);
+ GASSERT(flags & GBINDER_TX_FLAG_ONEWAY);
+ if (info) {
+ int p = RADIO_OBSERVER_PRIORITY_HIGHEST;
+ const GQuark quark = radio_config_resp_quark(self, code);
+ const guint* signals = radio_config_signals +
+ SIGNAL_OBSERVE_RESPONSE_0;
+
+ radio_config_ref(self);
+
+ /* High-priority observers get notified first */
+ for (; p > RADIO_OBSERVER_PRIORITY_DEFAULT; p--) {
+ const int i = RADIO_OBSERVER_PRIORITY_INDEX(p);
+
+ if (signals[i]) {
+ g_signal_emit(self, signals[i], quark, code, info, &args);
+ }
+ }
+
+ /* Then the response is actually processed */
+ if (!radio_base_handle_resp(&self->base, code, info, &args)) {
+ const char* name = radio_config_known_resp_name(code);
+
+ /* Most likely this is a response to a cancelled request */
+ GDEBUG("Ignoring IRadioConfig response [%08x] %u %s",
+ info->serial, code, name ? name : "");
+ }
+
+ /* Followed by the remaining observers in their priority order */
+ for (; p >= RADIO_OBSERVER_PRIORITY_LOWEST; p--) {
+ const int i = RADIO_OBSERVER_PRIORITY_INDEX(p);
+
+ if (signals[i]) {
+ g_signal_emit(self, signals[i], quark, code, info, &args);
+ }
+ }
+ radio_config_unref(self);
+ *status = GBINDER_STATUS_OK;
+ }
+ }
+ return NULL;
+}
+
+static
+void
+radio_config_drop_binder(
+ RadioConfig* self)
+{
+ if (self->indication) {
+ gbinder_local_object_drop(self->indication);
+ self->indication = NULL;
+ }
+ if (self->response) {
+ gbinder_local_object_drop(self->response);
+ self->response = NULL;
+ }
+ if (self->remote) {
+ gbinder_remote_object_remove_handler(self->remote, self->death_id);
+ gbinder_remote_object_unref(self->remote);
+ self->death_id = 0;
+ self->remote = NULL;
+ }
+}
+
+static
+void
+radio_config_died(
+ GBinderRemoteObject* obj,
+ void* user_data)
+{
+ RadioConfig* self = THIS(user_data);
+
+ GWARN("IRadioConfig died");
+ self->dead = TRUE;
+ radio_config_ref(self);
+ radio_config_drop_binder(self);
+ if (radio_config_instance[self->version] == self) {
+ radio_config_instance[self->version] = NULL; /* Clear the cache */
+ }
+ g_signal_emit(self, radio_config_signals[SIGNAL_DEATH], 0);
+ radio_base_handle_death(&self->base);
+ radio_config_unref(self);
+}
+
+static
+void
+radio_config_gone(
+ gpointer user_data,
+ GObject* dead)
+{
+ GObject** shared_instance = user_data;
+
+ if (*shared_instance == dead) {
+ *shared_instance = NULL;
+ GVERBOSE_("IRadioConfig gone");
+ }
+}
+
+static
+RadioConfig*
+radio_config_create(
+ GBinderServiceManager* sm,
+ GBinderRemoteObject* remote,
+ const RadioConfigInterfaceDesc* desc)
+{
+ RadioConfig* self = g_object_new(THIS_TYPE, NULL);
+ GBinderLocalRequest* req;
+ GBinderWriter writer;
+ int status;
+
+ radio_base_initialize(&self->base);
+ self->version = desc->version;
+ self->remote = gbinder_remote_object_ref(remote);
+ self->client = gbinder_client_new2(remote, radio_config_iface_info,
+ G_N_ELEMENTS(radio_config_iface_info));
+ self->indication = gbinder_servicemanager_new_local_object2(sm,
+ desc->ind_ifaces, radio_config_indication, self);
+ self->response = gbinder_servicemanager_new_local_object2(sm,
+ desc->resp_ifaces, radio_config_response, self);
+ self->death_id = gbinder_remote_object_add_death_handler(remote,
+ radio_config_died, self);
+
+ /* IRadioConfig::setResponseFunctions */
+ req = gbinder_client_new_request2(self->client,
+ RADIO_CONFIG_REQ_SET_RESPONSE_FUNCTIONS);
+ gbinder_local_request_init_writer(req, &writer);
+ gbinder_writer_append_local_object(&writer, self->response);
+ gbinder_writer_append_local_object(&writer, self->indication);
+ gbinder_remote_reply_unref(gbinder_client_transact_sync_reply(self->client,
+ RADIO_CONFIG_REQ_SET_RESPONSE_FUNCTIONS, req, &status));
+ GVERBOSE_("IRadioConfig::setResponseFunctions status %d", status);
+ gbinder_local_request_unref(req);
+ return self;
+}
+
+/*==========================================================================*
+ * API
+ *==========================================================================*/
+
+RadioConfig*
+radio_config_new(
+ void)
+{
+ return radio_config_new_with_version(RADIO_CONFIG_INTERFACE_MAX);
+}
+
+RadioConfig*
+radio_config_new_with_version(
+ RADIO_CONFIG_INTERFACE max_version)
+{
+ /* Validate the requested version to avoid out-of-bounds access */
+ if (max_version < RADIO_CONFIG_INTERFACE_1_0) {
+ max_version = RADIO_CONFIG_INTERFACE_1_0;
+ } else if (max_version > RADIO_CONFIG_INTERFACE_MAX) {
+ max_version = RADIO_CONFIG_INTERFACE_MAX;
+ }
+
+ if (radio_config_instance[max_version]) {
+ /* The requested instance already exists */
+ return radio_config_ref(radio_config_instance[max_version]);
+ } else {
+ /* Assume /dev/hwbinder */
+ GBinderServiceManager* sm =
+ gbinder_servicemanager_new(GBINDER_DEFAULT_HWBINDER);
+
+ if (sm) {
+ guint i;
+ GBinderRemoteObject* obj = NULL; /* autoreleased */
+ const RadioConfigInterfaceDesc* desc;
+ RadioConfig* config = NULL;
+
+ /* Find maximum available version not exceeding the requested one */
+ for (i=0; i<G_N_ELEMENTS(radio_config_interfaces) && !obj; i++) {
+ desc = radio_config_interfaces + i;
+ if (desc->version <= max_version) {
+ obj = gbinder_servicemanager_get_service_sync(sm,
+ desc->fqname, NULL);
+ if (obj) {
+ /*
+ * desc->version isn't necessarily equal to
+ * max_version
+ */
+ if (radio_config_instance[desc->version]) {
+ config = radio_config_ref(radio_config_instance
+ [desc->version]);
+ } else {
+ GINFO("Connected to %s", desc->fqname);
+ config = radio_config_create(sm, obj, desc);
+ }
+ break;
+ }
+ }
+ }
+
+ gbinder_servicemanager_unref(sm);
+ if (config) {
+ radio_config_instance[desc->version] = config;
+ g_object_weak_ref(G_OBJECT(config), radio_config_gone,
+ radio_config_instance + desc->version);
+ return config;
+ }
+ }
+ }
+ return NULL;
+}
+
+RadioConfig*
+radio_config_ref(
+ RadioConfig* self)
+{
+ if (G_LIKELY(self)) {
+ g_object_ref(self);
+ }
+ return self;
+}
+
+void
+radio_config_unref(
+ RadioConfig* self)
+{
+ if (G_LIKELY(self)) {
+ g_object_unref(self);
+ }
+}
+
+gboolean
+radio_config_dead(
+ RadioConfig* self)
+{
+ return G_UNLIKELY(!self) || self->dead;
+}
+
+RADIO_CONFIG_INTERFACE
+radio_config_interface(
+ RadioConfig* self)
+{
+ return G_LIKELY(self) ? self->version : RADIO_CONFIG_INTERFACE_NONE;
+}
+
+gsize
+radio_config_rpc_header_size(
+ RadioConfig* self,
+ RADIO_CONFIG_REQ req)
+{
+ if (G_LIKELY(self)) {
+ GBytes* header = gbinder_client_rpc_header(self->client, req);
+
+ if (header) {
+ return g_bytes_get_size(header);
+ }
+ }
+ return 0;
+}
+
+const char*
+radio_config_req_name(
+ RadioConfig* self,
+ RADIO_CONFIG_REQ req)
+{
+ const char* known = radio_config_known_req_name(req);
+
+ if (known) {
+ return known;
+ } else if (G_LIKELY(self)) {
+ char* str = g_strdup_printf("%u", (guint)req);
+
+ gutil_idle_pool_add(self->pool, str, g_free);
+ return str;
+ } else {
+ return NULL;
+ }
+}
+
+const char*
+radio_config_resp_name(
+ RadioConfig* self,
+ RADIO_CONFIG_RESP resp)
+{
+ const char* known = radio_config_known_resp_name(resp);
+
+ if (known) {
+ return known;
+ } else if (G_LIKELY(self)) {
+ char* str = g_strdup_printf("%u", (guint)resp);
+
+ gutil_idle_pool_add(self->pool, str, g_free);
+ return str;
+ } else {
+ return NULL;
+ }
+}
+
+const char*
+radio_config_ind_name(
+ RadioConfig* self,
+ RADIO_CONFIG_IND ind)
+{
+ const char* known = radio_config_known_ind_name(ind);
+
+ if (known) {
+ return known;
+ } else if (G_LIKELY(self)) {
+ char* str = g_strdup_printf("%u", (guint)ind);
+
+ gutil_idle_pool_add(self->pool, str, g_free);
+ return str;
+ } else {
+ return NULL;
+ }
+}
+
+gulong
+radio_config_add_death_handler(
+ RadioConfig* self,
+ RadioConfigFunc fn,
+ gpointer user_data)
+{
+ return (G_LIKELY(self) && G_LIKELY(fn)) ?
+ g_signal_connect_closure_by_id(self,
+ radio_config_signals[SIGNAL_DEATH], 0,
+ g_cclosure_new(G_CALLBACK(fn), user_data, NULL), FALSE) : 0;
+}
+
+gulong
+radio_config_add_request_observer(
+ RadioConfig* self,
+ RADIO_CONFIG_REQ code,
+ RadioConfigRequestObserverFunc func,
+ gpointer user_data)
+{
+ return radio_config_add_request_observer_with_priority(self,
+ RADIO_OBSERVER_PRIORITY_DEFAULT, code, func, user_data);
+}
+
+gulong
+radio_config_add_request_observer_with_priority(
+ RadioConfig* self,
+ RADIO_OBSERVER_PRIORITY priority,
+ RADIO_CONFIG_REQ code,
+ RadioConfigRequestObserverFunc func,
+ gpointer user_data)
+{
+ if (G_LIKELY(self) && G_LIKELY(func)) {
+ const guint index = radio_observer_priority_index(priority);
+ const RADIO_CONFIG_SIGNAL sig = SIGNAL_OBSERVE_REQUEST_0 + index;
+
+ /* Register signal on demand */
+ if (!radio_config_signals[sig]) {
+ radio_config_signals[sig] =
+ g_signal_new(radio_config_signal_observe_request_name[index],
+ THIS_TYPE, G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
+ 0, NULL, NULL, NULL, G_TYPE_NONE,
+ 2, G_TYPE_UINT, G_TYPE_POINTER);
+ }
+
+ return g_signal_connect_closure_by_id(self,
+ radio_config_signals[sig],
+ radio_config_req_quark(self, code),
+ g_cclosure_new(G_CALLBACK(func), user_data, NULL), FALSE);
+ }
+ return 0;
+}
+
+gulong
+radio_config_add_response_observer(
+ RadioConfig* self,
+ RADIO_CONFIG_RESP code,
+ RadioConfigResponseObserverFunc func,
+ gpointer user_data)
+{
+ return radio_config_add_response_observer_with_priority(self,
+ RADIO_OBSERVER_PRIORITY_DEFAULT, code, func, user_data);
+}
+
+gulong
+radio_config_add_response_observer_with_priority(
+ RadioConfig* self,
+ RADIO_OBSERVER_PRIORITY priority,
+ RADIO_CONFIG_RESP code,
+ RadioConfigResponseObserverFunc func,
+ gpointer user_data)
+{
+ if (G_LIKELY(self) && G_LIKELY(func)) {
+ const guint index = radio_observer_priority_index(priority);
+ const RADIO_CONFIG_SIGNAL sig = SIGNAL_OBSERVE_RESPONSE_0 + index;
+
+ /* Register signal on demand */
+ if (!radio_config_signals[sig]) {
+ radio_config_signals[sig] =
+ g_signal_new(radio_config_signal_observe_response_name[index],
+ THIS_TYPE, G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
+ 0, NULL, NULL, NULL, G_TYPE_NONE,
+ 3, G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_POINTER);
+ }
+
+ return g_signal_connect_closure_by_id(self,
+ radio_config_signals[sig],
+ radio_config_resp_quark(self, code),
+ g_cclosure_new(G_CALLBACK(func), user_data, NULL), FALSE);
+ }
+ return 0;
+}
+
+gulong
+radio_config_add_indication_observer(
+ RadioConfig* self,
+ RADIO_CONFIG_IND code,
+ RadioConfigIndicationObserverFunc func,
+ gpointer user_data)
+{
+ return radio_config_add_indication_observer_with_priority(self,
+ RADIO_OBSERVER_PRIORITY_DEFAULT, code, func, user_data);
+}
+
+gulong
+radio_config_add_indication_observer_with_priority(
+ RadioConfig* self,
+ RADIO_OBSERVER_PRIORITY priority,
+ RADIO_CONFIG_IND code,
+ RadioConfigIndicationObserverFunc func,
+ gpointer user_data) /* Since 1.4.3 */
+{
+ if (G_LIKELY(self) && G_LIKELY(func)) {
+ const guint pi = radio_observer_priority_index(priority);
+ const RADIO_CONFIG_SIGNAL sig = SIGNAL_OBSERVE_INDICATION_0 + pi;
+
+ /* Register signal on demand */
+ if (!radio_config_signals[sig]) {
+ radio_config_signals[sig] =
+ g_signal_new(radio_config_signal_observe_indication_name[pi],
+ THIS_TYPE, G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
+ 0, NULL, NULL, NULL, G_TYPE_NONE,
+ 2, G_TYPE_UINT, G_TYPE_POINTER);
+ }
+
+ return g_signal_connect_closure_by_id(self,
+ radio_config_signals[sig],
+ radio_config_ind_quark(self, code),
+ g_cclosure_new(G_CALLBACK(func), user_data, NULL), FALSE);
+ }
+ return 0;
+}
+
+void
+radio_config_remove_handler(
+ RadioConfig* self,
+ gulong id)
+{
+ if (G_LIKELY(self) && G_LIKELY(id)) {
+ g_signal_handler_disconnect(self, id);
+ }
+}
+
+void
+radio_config_remove_handlers(
+ RadioConfig* self,
+ gulong* ids,
+ int count)
+{
+ gutil_disconnect_handlers(self, ids, count);
+}
+
+/*==========================================================================*
+ * Methods
+ *==========================================================================*/
+
+static
+gboolean
+radio_config_is_dead(
+ RadioBase* base)
+{
+ return THIS(base)->dead;
+}
+
+static
+gboolean
+radio_config_can_submit_requests(
+ RadioBase* base)
+{
+ return !radio_config_is_dead(base);
+}
+
+static
+GBinderLocalRequest*
+radio_config_new_request(
+ RadioBase* base,
+ guint32 code)
+{
+ return gbinder_client_new_request2(THIS(base)->client, code);
+}
+
+static
+gulong
+radio_config_send_request(
+ RadioBase* base,
+ RadioRequest* req,
+ RadioBaseRequestSentFunc callback)
+{
+ RadioConfig* self = THIS(base);
+ RadioConfigCall* call = g_slice_new(RadioConfigCall);
+ GQuark quark = 0;
+ gulong tx_id;
+ int i;
+
+ call->object = base;
+ call->callback = callback;
+ call->req = radio_request_ref(req);
+
+ /* Notify the observers first */
+ for (i = RADIO_OBSERVER_PRIORITY_COUNT - 1; i >= 0; i--) {
+ guint id = radio_config_signals[SIGNAL_OBSERVE_REQUEST_0 + i];
+
+ if (id) {
+ if (!quark) {
+ quark = radio_config_req_quark(self, req->code);
+ }
+ g_signal_emit(self, id, quark, req->code, req->args);
+ }
+ }
+
+ /* Then actually submit the request */
+ tx_id = gbinder_client_transact(self->client, req->code,
+ GBINDER_TX_FLAG_ONEWAY, req->args, radio_config_call_complete,
+ (GDestroyNotify) radio_config_call_free, call);
+ if (tx_id) {
+ return tx_id;
+ } else {
+ radio_config_call_free(call);
+ return 0;
+ }
+}
+
+static
+void
+radio_config_cancel_request(
+ RadioBase* base,
+ gulong id)
+{
+ gbinder_client_cancel(THIS(base)->client, id);
+}
+
+/*==========================================================================*
+ * Internals
+ *==========================================================================*/
+
+static
+void
+radio_config_init(
+ RadioConfig* self)
+{
+ self->version = RADIO_CONFIG_INTERFACE_NONE;
+ self->pool = gutil_idle_pool_new();
+ self->req_quarks = g_hash_table_new(g_direct_hash, g_direct_equal);
+ self->resp_quarks = g_hash_table_new(g_direct_hash, g_direct_equal);
+ self->ind_quarks = g_hash_table_new(g_direct_hash, g_direct_equal);
+}
+
+static
+void
+radio_config_finalize(
+ GObject* object)
+{
+ RadioConfig* self = THIS(object);
+
+ radio_config_drop_binder(self);
+ gbinder_client_unref(self->client);
+ gutil_idle_pool_destroy(self->pool);
+ g_hash_table_destroy(self->req_quarks);
+ g_hash_table_destroy(self->resp_quarks);
+ g_hash_table_destroy(self->ind_quarks);
+ G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
+}
+
+static
+void
+radio_config_class_init(
+ RadioConfigClass* klass)
+{
+ RadioBaseClass* base_class = RADIO_BASE_CLASS(klass);
+ GObjectClass* object_class = G_OBJECT_CLASS(klass);
+ GType type = G_OBJECT_CLASS_TYPE(klass);
+
+ base_class->is_dead = radio_config_is_dead;
+ base_class->can_submit_requests = radio_config_can_submit_requests;
+ base_class->new_request = radio_config_new_request;
+ base_class->send_request = radio_config_send_request;
+ base_class->cancel_request = radio_config_cancel_request;
+ object_class->finalize = radio_config_finalize;
+
+ /* Priority-based signals are registered on demand */
+ radio_config_signals[SIGNAL_INDICATION] =
+ g_signal_new(SIGNAL_INDICATION_NAME, type,
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED, 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_POINTER);
+ radio_config_signals[SIGNAL_DEATH] =
+ g_signal_new(SIGNAL_DEATH_NAME, type, G_SIGNAL_RUN_FIRST, 0,
+ NULL, NULL, NULL, G_TYPE_NONE, 0);
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Changed |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/src/radio_instance.c
^
|
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2018-2021 Jolla Ltd.
- * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
+ * Copyright (C) 2018-2022 Jolla Ltd.
+ * Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
@@ -36,14 +36,15 @@
#define GLIB_DISABLE_DEPRECATION_WARNINGS
-#include "radio_instance.h"
+#include "radio_instance_p.h"
#include "radio_registry_p.h"
-#include "radio_util.h"
+#include "radio_util_p.h"
#include "radio_log.h"
#include <gbinder.h>
#include <gutil_idlepool.h>
+#include <gutil_macros.h>
#include <gutil_misc.h>
#include <gutil_strv.h>
@@ -56,6 +57,7 @@
GBinderRemoteObject* remote;
GBinderLocalObject* response;
GBinderLocalObject* indication;
+ GHashTable* req_quarks;
GHashTable* resp_quarks;
GHashTable* ind_quarks;
gulong death_id;
@@ -67,24 +69,52 @@
G_DEFINE_TYPE(RadioInstance, radio_instance, G_TYPE_OBJECT)
-enum radio_instance_signal {
- SIGNAL_HANDLE_INDICATION,
+typedef enum radio_instance_signal {
+ #define SIGNAL_INDEX(x) SIGNAL_OBSERVE_REQUEST_##x,
+ FOREACH_OBSERVER_PRIORITY(SIGNAL_INDEX)
+ #undef SIGNAL_INDEX
+ #define SIGNAL_INDEX(x) SIGNAL_OBSERVE_RESPONSE_##x,
+ FOREACH_OBSERVER_PRIORITY(SIGNAL_INDEX)
+ #undef SIGNAL_INDEX
+ #define SIGNAL_INDEX(x) SIGNAL_OBSERVE_INDICATION_##x,
+ FOREACH_OBSERVER_PRIORITY(SIGNAL_INDEX)
+ #undef SIGNAL_INDEX
SIGNAL_HANDLE_RESPONSE,
- SIGNAL_OBSERVE_INDICATION,
- SIGNAL_OBSERVE_RESPONSE,
+ SIGNAL_HANDLE_INDICATION,
SIGNAL_ACK,
SIGNAL_DEATH,
SIGNAL_ENABLED,
+ SIGNAL_CONNECTED,
SIGNAL_COUNT
+} RADIO_INSTANCE_SIGNAL;
+
+static const char* radio_instance_signal_observe_request_name[] = {
+ #define SIGNAL_NAME(x) "radio-instance-observe-request-" #x,
+ FOREACH_OBSERVER_PRIORITY(SIGNAL_NAME)
+ #undef SIGNAL_NAME
+ NULL
+};
+
+static const char* radio_instance_signal_observe_response_name[] = {
+ #define SIGNAL_NAME(x) "radio-instance-observe-response-" #x,
+ FOREACH_OBSERVER_PRIORITY(SIGNAL_NAME)
+ #undef SIGNAL_NAME
+ NULL
+};
+
+static const char* radio_instance_signal_observe_indication_name[] = {
+ #define SIGNAL_NAME(x) "radio-instance-observe-indication-" #x,
+ FOREACH_OBSERVER_PRIORITY(SIGNAL_NAME)
+ #undef SIGNAL_NAME
+ NULL
};
#define SIGNAL_HANDLE_INDICATION_NAME "radio-instance-handle-indication"
#define SIGNAL_HANDLE_RESPONSE_NAME "radio-instance-handle-response"
-#define SIGNAL_OBSERVE_INDICATION_NAME "radio-instance-observe-indication"
-#define SIGNAL_OBSERVE_RESPONSE_NAME "radio-instance-observe-response"
#define SIGNAL_ACK_NAME "radio-instance-ack"
#define SIGNAL_DEATH_NAME "radio-instance-death"
#define SIGNAL_ENABLED_NAME "radio-instance-enabled"
+#define SIGNAL_CONNECTED_NAME "radio-instance-connected"
static guint radio_instance_signals[SIGNAL_COUNT] = { 0 };
@@ -93,6 +123,7 @@
#define DEFAULT_INTERFACE RADIO_INTERFACE_1_0
static const GBinderClientIfaceInfo radio_iface_info[] = {
+ {RADIO_1_5, RADIO_1_5_REQ_LAST },
{RADIO_1_4, RADIO_1_4_REQ_LAST },
{RADIO_1_3, RADIO_1_3_REQ_LAST },
{RADIO_1_2, RADIO_1_2_REQ_LAST },
@@ -102,6 +133,7 @@
G_STATIC_ASSERT(G_N_ELEMENTS(radio_iface_info) == RADIO_INTERFACE_COUNT);
static const char* const radio_indication_ifaces[] = {
+ RADIO_INDICATION_1_5,
RADIO_INDICATION_1_4,
RADIO_INDICATION_1_3,
RADIO_INDICATION_1_2,
@@ -112,6 +144,7 @@
G_STATIC_ASSERT(G_N_ELEMENTS(radio_indication_ifaces) == RADIO_INTERFACE_COUNT + 1);
static const char* const radio_response_ifaces[] = {
+ RADIO_RESPONSE_1_5,
RADIO_RESPONSE_1_4,
RADIO_RESPONSE_1_3,
RADIO_RESPONSE_1_2,
@@ -136,6 +169,7 @@
radio_response_ifaces + RADIO_INTERFACE_INDEX(RADIO_INTERFACE_##v)
static const RadioInterfaceDesc radio_interfaces[] = {
+ { RADIO_INTERFACE_DESC(1_5) },
{ RADIO_INTERFACE_DESC(1_4) },
{ RADIO_INTERFACE_DESC(1_3) },
{ RADIO_INTERFACE_DESC(1_2) },
@@ -144,32 +178,41 @@
};
G_STATIC_ASSERT(G_N_ELEMENTS(radio_interfaces) == RADIO_INTERFACE_COUNT);
+typedef struct radio_instance_tx {
+ RadioInstance* instance;
+ RadioInstanceTxCompleteFunc complete;
+ RadioInstanceTxDestroyFunc destroy;
+ gulong id;
+ void* user_data1;
+ void* user_data2;
+} RadioInstanceTx;
+
/*==========================================================================*
* Implementation
*==========================================================================*/
static
GQuark
-radio_instance_ind_quark(
+radio_instance_req_quark(
RadioInstance* self,
- RADIO_IND ind)
+ RADIO_REQ req)
{
GQuark q = 0;
- if (ind != RADIO_IND_ANY) {
+ if (req != RADIO_REQ_ANY) {
RadioInstancePriv* priv = self->priv;
- gpointer key = GUINT_TO_POINTER(ind);
+ gpointer key = GUINT_TO_POINTER(req);
- q = GPOINTER_TO_UINT(g_hash_table_lookup(priv->ind_quarks, key));
+ q = GPOINTER_TO_UINT(g_hash_table_lookup(priv->req_quarks, key));
if (!q) {
- const char* known = radio_ind_name(ind);
+ const char* known = radio_req_name(req);
if (known) {
q = g_quark_from_static_string(known);
} else {
- q = g_quark_from_string(radio_instance_ind_name(self, ind));
+ q = g_quark_from_string(radio_instance_req_name(self, req));
}
- g_hash_table_insert(priv->ind_quarks, key, GUINT_TO_POINTER(q));
+ g_hash_table_insert(priv->req_quarks, key, GUINT_TO_POINTER(q));
}
}
return q;
@@ -203,6 +246,28 @@
}
static
+void
+radio_instance_notify_request_observers(
+ RadioInstance* self,
+ RADIO_REQ code,
+ GBinderLocalRequest* args)
+{
+ GQuark quark = 0;
+ int i;
+
+ for (i = RADIO_OBSERVER_PRIORITY_COUNT - 1; i >= 0; i--) {
+ guint id = radio_instance_signals[SIGNAL_OBSERVE_REQUEST_0 + i];
+
+ if (id) {
+ if (!quark) {
+ quark = radio_instance_req_quark(self, code);
+ }
+ g_signal_emit(self, id, quark, code, args);
+ }
+ }
+}
+
+static
GBinderLocalReply*
radio_instance_indication(
GBinderLocalObject* obj,
@@ -224,15 +289,49 @@
gbinder_remote_request_init_reader(req, &reader);
if (gbinder_reader_read_uint32(&reader, &type) &&
(type == RADIO_IND_UNSOLICITED || type == RADIO_IND_ACK_EXP)) {
- GQuark quark = radio_instance_ind_quark(self, code);
+ const GQuark quark = radio_instance_ind_quark(self, code);
+ const guint* signals = radio_instance_signals +
+ SIGNAL_OBSERVE_INDICATION_0;
+ int p = RADIO_OBSERVER_PRIORITY_HIGHEST;
gboolean handled = FALSE;
- g_signal_emit(self,
- radio_instance_signals[SIGNAL_HANDLE_INDICATION], quark,
- code, type, &reader, &handled);
- g_signal_emit(self,
- radio_instance_signals[SIGNAL_OBSERVE_INDICATION], quark,
- code, type, &reader);
+ /* High-priority observers are notified first */
+ for (; p > RADIO_OBSERVER_PRIORITY_DEFAULT; p--) {
+ if (signals[RADIO_OBSERVER_PRIORITY_INDEX(p)]) {
+ g_signal_emit(self, signals
+ [RADIO_OBSERVER_PRIORITY_INDEX(p)],
+ quark, code, type, &reader);
+ }
+ }
+
+ /* rilConnected is a special case */
+ if (code == RADIO_IND_RIL_CONNECTED) {
+ if (G_UNLIKELY(self->connected)) {
+ /* We are only supposed to receive it once */
+ GWARN("%s received unexpected rilConnected", self->slot);
+ } else {
+ GDEBUG("%s connected", self->slot);
+ self->connected = TRUE;
+ g_signal_emit(self, radio_instance_signals
+ [SIGNAL_CONNECTED], 0);
+ }
+ }
+
+ /* Notify handlers */
+ g_signal_emit(self, radio_instance_signals
+ [SIGNAL_HANDLE_INDICATION],
+ quark, code, type, &reader, &handled);
+
+ /* And then remaining observers in their priority order */
+ for (; p >= RADIO_OBSERVER_PRIORITY_LOWEST; p--) {
+ if (signals[RADIO_OBSERVER_PRIORITY_INDEX(p)]) {
+ g_signal_emit(self, signals
+ [RADIO_OBSERVER_PRIORITY_INDEX(p)],
+ quark, code, type, &reader);
+ }
+ }
+
+ /* Ack unhandled indications */
if (type == RADIO_IND_ACK_EXP && !handled) {
GDEBUG("ack unhandled indication");
radio_instance_ack(self);
@@ -263,34 +362,56 @@
const char* iface = gbinder_remote_request_interface(req);
if (gutil_strv_contains((const GStrV*)radio_response_ifaces, iface)) {
+ GBinderReader reader;
+
/* All these should be one-way transactions */
GASSERT(flags & GBINDER_TX_FLAG_ONEWAY);
+ gbinder_remote_request_init_reader(req, &reader);
if (code == RADIO_RESP_ACKNOWLEDGE_REQUEST) {
/* oneway acknowledgeRequest(int32_t serial) */
gint32 serial;
GDEBUG("%s %u acknowledgeRequest", iface, code);
- if (gbinder_remote_request_read_int32(req, &serial)) {
+ if (gbinder_reader_read_int32(&reader, &serial)) {
g_signal_emit(self, radio_instance_signals[SIGNAL_ACK], 0,
serial);
}
} else {
/* All other responses have RadioResponseInfo */
- GBinderReader reader;
- const RadioResponseInfo* info;
+ const RadioResponseInfo* info =
+ gbinder_reader_read_hidl_struct(&reader, RadioResponseInfo);
- gbinder_remote_request_init_reader(req, &reader);
- info = gbinder_reader_read_hidl_struct(&reader, RadioResponseInfo);
if (info) {
- GQuark quark = radio_instance_resp_quark(self, code);
+ const GQuark quark = radio_instance_resp_quark(self, code);
+ const guint* signals = radio_instance_signals +
+ SIGNAL_OBSERVE_RESPONSE_0;
+ int p = RADIO_OBSERVER_PRIORITY_HIGHEST;
gboolean handled = FALSE;
- g_signal_emit(self,
- radio_instance_signals[SIGNAL_HANDLE_RESPONSE], quark,
- code, info, &reader, &handled);
- g_signal_emit(self,
- radio_instance_signals[SIGNAL_OBSERVE_RESPONSE], quark,
- code, info, &reader);
+ /* High-priority observers are notified first */
+ for (; p > RADIO_OBSERVER_PRIORITY_DEFAULT; p--) {
+ if (signals[RADIO_OBSERVER_PRIORITY_INDEX(p)]) {
+ g_signal_emit(self, signals
+ [RADIO_OBSERVER_PRIORITY_INDEX(p)],
+ quark, code, info, &reader);
+ }
+ }
+
+ /* Then handlers */
+ g_signal_emit(self, radio_instance_signals
+ [SIGNAL_HANDLE_RESPONSE],
+ quark, code, info, &reader, &handled);
+
+ /* And then remaining observers in their priority order */
+ for (; p >= RADIO_OBSERVER_PRIORITY_LOWEST; p--) {
+ if (signals[RADIO_OBSERVER_PRIORITY_INDEX(p)]) {
+ g_signal_emit(self, signals
+ [RADIO_OBSERVER_PRIORITY_INDEX(p)],
+ quark, code, info, &reader);
+ }
+ }
+
+ /* Ack unhandled responses */
if (info->type == RADIO_RESP_SOLICITED_ACK_EXP && !handled) {
GDEBUG("ack unhandled response");
radio_instance_ack(self);
@@ -353,6 +474,7 @@
RadioInstance* self = RADIO_INSTANCE(user_data);
self->dead = TRUE;
+ self->connected = FALSE;
GWARN("%s died", self->key);
radio_instance_ref(self);
radio_instance_drop_binder(self);
@@ -369,7 +491,6 @@
{
char* key = key_ptr;
- GASSERT(radio_instance_table);
GVERBOSE_("%s", key);
radio_instance_remove(key);
g_free(key);
@@ -427,7 +548,8 @@
* Don't destroy GBinderServiceManager right away in case if we
* have another slot to initialize.
*/
- gutil_idle_pool_add_object(priv->idle, g_object_ref(sm));
+ gutil_idle_pool_add(priv->idle, gbinder_servicemanager_ref(sm),
+ (GDestroyNotify) gbinder_servicemanager_unref);
return self;
}
@@ -457,8 +579,8 @@
if (obj) {
GINFO("Connected to %s", fqname);
- self = radio_instance_create_version(sm, obj, dev, slot, key,
- modem, slot_index, desc);
+ self = radio_instance_create_version(sm, obj, dev, slot,
+ key, modem, slot_index, desc);
}
g_free(fqname);
}
@@ -478,6 +600,124 @@
return g_strdup_printf("%s:%s:%d", dev, name, version);
}
+static
+void
+radio_instance_tx_free(
+ RadioInstanceTx* tx)
+{
+ radio_instance_unref(tx->instance);
+ gutil_slice_free(tx);
+}
+
+static
+void
+radio_instance_tx_destroy(
+ gpointer tx_data)
+{
+ RadioInstanceTx* tx = tx_data;
+
+ if (tx->destroy) {
+ tx->destroy(tx->user_data1, tx->user_data2);
+ }
+ radio_instance_tx_free(tx);
+}
+
+static
+void
+radio_instance_tx_complete(
+ GBinderClient* client,
+ GBinderRemoteReply* reply,
+ int status,
+ void* tx_data)
+{
+ RadioInstanceTx* tx = tx_data;
+
+ if (tx->complete) {
+ tx->complete(tx->instance, tx->id, status, tx->user_data1,
+ tx->user_data2);
+ }
+}
+
+/*==========================================================================*
+ * Internal API
+ *==========================================================================*/
+
+gulong
+radio_instance_send_request(
+ RadioInstance* self,
+ RADIO_REQ code,
+ GBinderLocalRequest* args,
+ RadioInstanceTxCompleteFunc complete,
+ RadioInstanceTxDestroyFunc destroy,
+ void* user_data1,
+ void* user_data2)
+{
+ if (G_LIKELY(self)) {
+ RadioInstancePriv* priv = self->priv;
+
+ if (complete || destroy) {
+ RadioInstanceTx* tx = g_slice_new(RadioInstanceTx);
+
+ tx->instance = radio_instance_ref(self);
+ tx->complete = complete;
+ tx->destroy = destroy;
+ tx->user_data1 = user_data1;
+ tx->user_data2 = user_data2;
+ radio_instance_notify_request_observers(self, code, args);
+ tx->id = gbinder_client_transact(priv->client, code,
+ GBINDER_TX_FLAG_ONEWAY, args, radio_instance_tx_complete,
+ radio_instance_tx_destroy, tx);
+ if (tx->id) {
+ return tx->id;
+ } else {
+ radio_instance_tx_free(tx);
+ }
+ } else {
+ /* No need to allocate the context */
+ radio_instance_notify_request_observers(self, code, args);
+ return gbinder_client_transact(priv->client, code,
+ GBINDER_TX_FLAG_ONEWAY, args, NULL, NULL, NULL);
+ }
+ }
+ return 0;
+}
+
+void
+radio_instance_cancel_request(
+ RadioInstance* self,
+ gulong id)
+{
+ if (G_LIKELY(self)) {
+ gbinder_client_cancel(self->priv->client, id);
+ }
+}
+
+GQuark
+radio_instance_ind_quark(
+ RadioInstance* self,
+ RADIO_IND ind)
+{
+ GQuark q = 0;
+
+ if (ind != RADIO_IND_ANY) {
+ RadioInstancePriv* priv = self->priv;
+ gpointer key = GUINT_TO_POINTER(ind);
+
+ q = GPOINTER_TO_UINT(g_hash_table_lookup(priv->ind_quarks, key));
+ if (!q) {
+ const char* known = radio_ind_name(ind);
+
+ if (known) {
+ q = g_quark_from_static_string(known);
+ } else {
+ q = g_quark_from_string(radio_instance_ind_name(self, ind));
+ }
+ g_hash_table_insert(priv->ind_quarks, key, GUINT_TO_POINTER(q));
+ }
+ }
+ return q;
+}
+
/*==========================================================================*
* API
*==========================================================================*/
@@ -589,12 +829,10 @@
{
RadioInstance* self = NULL;
- if (dev && dev[0] && name && name[0]) {
+ if (dev && dev[0] && name && name[0] && radio_instance_table) {
char* key = radio_instance_make_key(dev, name, version);
- if (radio_instance_table) {
- self = g_hash_table_lookup(radio_instance_table, key);
- }
+ self = g_hash_table_lookup(radio_instance_table, key);
g_free(key);
}
return self;
@@ -646,6 +884,22 @@
}
}
+gsize
+radio_instance_rpc_header_size(
+ RadioInstance* self,
+ RADIO_REQ req) /* Since 1.4.3 */
+{
+ if (G_LIKELY(self)) {
+ RadioInstancePriv* priv = self->priv;
+ GBytes* header = gbinder_client_rpc_header(priv->client, req);
+
+ if (header) {
+ return g_bytes_get_size(header);
+ }
+ }
+ return 0;
+}
+
const char*
radio_instance_req_name(
RadioInstance* self,
@@ -703,7 +957,6 @@
}
}
-
gboolean
radio_instance_is_dead(
RadioInstance* self)
@@ -716,8 +969,11 @@
RadioInstance* self)
{
if (G_LIKELY(self)) {
- return gbinder_client_transact_sync_oneway(self->priv->client,
- RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT, NULL) >= 0;
+ GBinderClient* client = self->priv->client;
+ const RADIO_REQ code = RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT;
+
+ radio_instance_notify_request_observers(self, code, NULL);
+ return gbinder_client_transact_sync_oneway(client, code, NULL) >= 0;
}
return 0;
}
@@ -740,8 +996,10 @@
GBinderLocalRequest* args)
{
if (G_LIKELY(self)) {
- return gbinder_client_transact_sync_oneway(self->priv->client,
- code, args) >= 0;
+ GBinderClient* client = self->priv->client;
+
+ radio_instance_notify_request_observers(self, code, args);
+ return gbinder_client_transact_sync_oneway(client, code, args) >= 0;
}
return FALSE;
}
@@ -759,57 +1017,153 @@
}
gulong
-radio_instance_add_indication_handler(
+radio_instance_add_request_observer(
RadioInstance* self,
- RADIO_IND ind,
- RadioIndicationHandlerFunc func,
+ RADIO_REQ code,
+ RadioRequestObserverFunc func,
+ gpointer user_data) /* Since 1.4.3 */
+{
+ return radio_instance_add_request_observer_with_priority(self,
+ RADIO_OBSERVER_PRIORITY_DEFAULT, code, func, user_data);
+}
+
+gulong
+radio_instance_add_request_observer_with_priority(
+ RadioInstance* self,
+ RADIO_OBSERVER_PRIORITY priority,
+ RADIO_REQ code,
+ RadioRequestObserverFunc func,
+ gpointer user_data) /* Since 1.4.3 */
+{
+ if (G_LIKELY(self) && G_LIKELY(func)) {
+ const guint index = radio_observer_priority_index(priority);
+ const RADIO_INSTANCE_SIGNAL sig = SIGNAL_OBSERVE_REQUEST_0 + index;
+
+ /* Register signal on demand */
+ if (!radio_instance_signals[sig]) {
+ radio_instance_signals[sig] =
+ g_signal_new(radio_instance_signal_observe_request_name
+ [index], RADIO_TYPE_INSTANCE,
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
+ 0, NULL, NULL, NULL, G_TYPE_NONE,
+ 2, G_TYPE_UINT, G_TYPE_POINTER);
+ }
+
+ return g_signal_connect_closure_by_id(self,
+ radio_instance_signals[sig],
+ radio_instance_req_quark(self, code),
+ g_cclosure_new(G_CALLBACK(func), user_data, NULL), FALSE);
+ }
+ return 0;
+}
+
+gulong
+radio_instance_add_response_observer(
+ RadioInstance* self,
+ RADIO_RESP code,
+ RadioResponseObserverFunc func,
gpointer user_data)
{
- return (G_LIKELY(self) && G_LIKELY(func)) ?
- g_signal_connect_closure_by_id(self,
- radio_instance_signals[SIGNAL_HANDLE_INDICATION],
- radio_instance_ind_quark(self, ind),
- g_cclosure_new(G_CALLBACK(func), user_data, NULL), FALSE) : 0;
+ return radio_instance_add_response_observer_with_priority(self,
+ RADIO_OBSERVER_PRIORITY_DEFAULT, code, func, user_data);
+}
+
+gulong
+radio_instance_add_response_observer_with_priority(
+ RadioInstance* self,
+ RADIO_OBSERVER_PRIORITY priority,
+ RADIO_RESP code,
+ RadioResponseObserverFunc func,
+ gpointer user_data) /* Since 1.4.3 */
+{
+ if (G_LIKELY(self) && G_LIKELY(func)) {
+ const guint index = radio_observer_priority_index(priority);
+ const RADIO_INSTANCE_SIGNAL sig = SIGNAL_OBSERVE_RESPONSE_0 + index;
+
+ /* Register signal on demand */
+ if (!radio_instance_signals[sig]) {
+ radio_instance_signals[sig] =
+ g_signal_new(radio_instance_signal_observe_response_name
+ [index], RADIO_TYPE_INSTANCE,
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
+ 0, NULL, NULL, NULL, G_TYPE_NONE,
+ 3, G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_POINTER);
+ }
+
+ return g_signal_connect_closure_by_id(self,
+ radio_instance_signals[sig],
+ radio_instance_resp_quark(self, code),
+ g_cclosure_new(G_CALLBACK(func), user_data, NULL), FALSE);
+ }
+ return 0;
}
gulong
radio_instance_add_indication_observer(
RadioInstance* self,
- RADIO_IND ind,
+ RADIO_IND code,
RadioIndicationObserverFunc func,
gpointer user_data)
{
- return (G_LIKELY(self) && G_LIKELY(func)) ?
- g_signal_connect_closure_by_id(self,
- radio_instance_signals[SIGNAL_OBSERVE_INDICATION],
- radio_instance_ind_quark(self, ind),
- g_cclosure_new(G_CALLBACK(func), user_data, NULL), FALSE) : 0;
+ return radio_instance_add_indication_observer_with_priority(self,
+ RADIO_OBSERVER_PRIORITY_DEFAULT, code, func, user_data);
+}
+
+gulong
+radio_instance_add_indication_observer_with_priority(
+ RadioInstance* self,
+ RADIO_OBSERVER_PRIORITY priority,
+ RADIO_IND code,
+ RadioIndicationObserverFunc func,
+ gpointer user_data) /* Since 1.4.3 */
+{
+ if (G_LIKELY(self) && G_LIKELY(func)) {
+ const guint index = radio_observer_priority_index(priority);
+ const RADIO_INSTANCE_SIGNAL sig = SIGNAL_OBSERVE_INDICATION_0 + index;
+
+ /* Register signal on demand */
+ if (!radio_instance_signals[sig]) {
+ radio_instance_signals[sig] =
+ g_signal_new(radio_instance_signal_observe_indication_name
+ [index], RADIO_TYPE_INSTANCE,
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED,
+ 0, NULL, NULL, NULL, G_TYPE_NONE,
+ 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_POINTER);
+ }
+
+ return g_signal_connect_closure_by_id(self,
+ radio_instance_signals[sig],
+ radio_instance_ind_quark(self, code),
+ g_cclosure_new(G_CALLBACK(func), user_data, NULL), FALSE);
+ }
+ return 0;
}
+
gulong
radio_instance_add_response_handler(
RadioInstance* self,
- RADIO_RESP resp,
+ RADIO_RESP code,
RadioResponseHandlerFunc func,
gpointer user_data)
{
return (G_LIKELY(self) && G_LIKELY(func)) ?
g_signal_connect_closure_by_id(self,
radio_instance_signals[SIGNAL_HANDLE_RESPONSE],
- radio_instance_resp_quark(self, resp),
+ radio_instance_resp_quark(self, code),
g_cclosure_new(G_CALLBACK(func), user_data, NULL), FALSE) : 0;
}
gulong
-radio_instance_add_response_observer(
+radio_instance_add_indication_handler(
RadioInstance* self,
- RADIO_RESP resp,
- RadioResponseObserverFunc func,
+ RADIO_IND code,
+ RadioIndicationHandlerFunc func,
gpointer user_data)
{
return (G_LIKELY(self) && G_LIKELY(func)) ?
g_signal_connect_closure_by_id(self,
- radio_instance_signals[SIGNAL_OBSERVE_RESPONSE],
- radio_instance_resp_quark(self, resp),
+ radio_instance_signals[SIGNAL_HANDLE_INDICATION],
+ radio_instance_ind_quark(self, code),
g_cclosure_new(G_CALLBACK(func), user_data, NULL), FALSE) : 0;
}
@@ -843,6 +1197,16 @@
SIGNAL_ENABLED_NAME, G_CALLBACK(func), user_data) : 0;
}
+gulong
+radio_instance_add_connected_handler(
+ RadioInstance* self,
+ RadioInstanceFunc func,
+ gpointer user_data) /* Since 1.4.3 */
+{
+ return (G_LIKELY(self) && G_LIKELY(func)) ? g_signal_connect(self,
+ SIGNAL_CONNECTED_NAME, G_CALLBACK(func), user_data) : 0;
+}
+
void
radio_instance_remove_handler(
RadioInstance* self,
@@ -876,6 +1240,7 @@
self->priv = priv;
priv->idle = gutil_idle_pool_new();
+ priv->req_quarks = g_hash_table_new(g_direct_hash, g_direct_equal);
priv->resp_quarks = g_hash_table_new(g_direct_hash, g_direct_equal);
priv->ind_quarks = g_hash_table_new(g_direct_hash, g_direct_equal);
}
@@ -891,6 +1256,7 @@
radio_instance_drop_binder(self);
gbinder_client_unref(priv->client);
gutil_idle_pool_destroy(priv->idle);
+ g_hash_table_destroy(priv->req_quarks);
g_hash_table_destroy(priv->resp_quarks);
g_hash_table_destroy(priv->ind_quarks);
g_free(priv->slot);
@@ -911,24 +1277,17 @@
g_type_class_add_private(klass, sizeof(RadioInstancePriv));
object_class->finalize = radio_instance_finalize;
- radio_instance_signals[SIGNAL_HANDLE_INDICATION] =
- g_signal_new(SIGNAL_HANDLE_INDICATION_NAME, type,
- G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0,
- g_signal_accumulator_true_handled, NULL, NULL,
- G_TYPE_BOOLEAN, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_POINTER);
+ /* Priority-based signals are registered on demand */
radio_instance_signals[SIGNAL_HANDLE_RESPONSE] =
g_signal_new(SIGNAL_HANDLE_RESPONSE_NAME, type,
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0,
g_signal_accumulator_true_handled, NULL, NULL,
G_TYPE_BOOLEAN, 3, G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_POINTER);
- radio_instance_signals[SIGNAL_OBSERVE_INDICATION] =
- g_signal_new(SIGNAL_OBSERVE_INDICATION_NAME, type,
- G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED, 0, NULL, NULL, NULL,
- G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_POINTER);
- radio_instance_signals[SIGNAL_OBSERVE_RESPONSE] =
- g_signal_new(SIGNAL_OBSERVE_RESPONSE_NAME, type,
- G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED, 0, NULL, NULL, NULL,
- G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_POINTER);
+ radio_instance_signals[SIGNAL_HANDLE_INDICATION] =
+ g_signal_new(SIGNAL_HANDLE_INDICATION_NAME, type,
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0,
+ g_signal_accumulator_true_handled, NULL, NULL,
+ G_TYPE_BOOLEAN, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_POINTER);
radio_instance_signals[SIGNAL_ACK] =
g_signal_new(SIGNAL_ACK_NAME, type,
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL,
@@ -941,6 +1300,10 @@
g_signal_new(SIGNAL_ENABLED_NAME, type,
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
+ radio_instance_signals[SIGNAL_CONNECTED] =
+ g_signal_new(SIGNAL_CONNECTED_NAME, type,
+ G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
}
/*
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/src/radio_instance_p.h
^
|
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2021 Jolla Ltd.
+ * Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#ifndef RADIO_INSTANCE_PRIVATE_H
+#define RADIO_INSTANCE_PRIVATE_H
+
+#include "radio_types_p.h"
+#include "radio_instance.h"
+
+typedef
+void
+(*RadioInstanceTxCompleteFunc)(
+ RadioInstance* instance,
+ gulong id,
+ int status,
+ void* user_data1,
+ void* user_data2);
+
+typedef
+void
+(*RadioInstanceTxDestroyFunc)(
+ void* user_data1,
+ void* user_data2);
+
+gulong
+radio_instance_send_request(
+ RadioInstance* instance,
+ RADIO_REQ code,
+ GBinderLocalRequest* args,
+ RadioInstanceTxCompleteFunc complete,
+ RadioInstanceTxDestroyFunc destroy,
+ void* user_data1,
+ void* user_data2)
+ RADIO_INTERNAL;
+
+void
+radio_instance_cancel_request(
+ RadioInstance* instance,
+ gulong id)
+ RADIO_INTERNAL;
+
+GQuark
+radio_instance_ind_quark(
+ RadioInstance* instance,
+ RADIO_IND ind)
+ RADIO_INTERNAL;
+
+#endif /* RADIO_INSTANCE_PRIVATE_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Changed |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/src/radio_registry.c
^
|
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2018-2019 Jolla Ltd.
- * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
+ * Copyright (C) 2018-2021 Jolla Ltd.
+ * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
@@ -44,6 +44,7 @@
GObject parent;
};
+GType radio_registry_get_type(void) RADIO_INTERNAL;
G_DEFINE_TYPE(RadioRegistry, radio_registry, G_TYPE_OBJECT)
#define RADIO_TYPE_REGISTRY (radio_registry_get_type())
#define RADIO_REGISTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
@@ -110,7 +111,7 @@
(gpointer*)(&radio_registry_instance));
}
return radio_registry_instance;
-
+
}
RadioRegistry*
|
[-]
[+]
|
Changed |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/src/radio_registry_p.h
^
|
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2018-2020 Jolla Ltd.
- * Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
+ * Copyright (C) 2018-2021 Jolla Ltd.
+ * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
@@ -37,17 +37,18 @@
#ifndef RADIO_REGISTRY_PRIVATE_H
#define RADIO_REGISTRY_PRIVATE_H
+#include "radio_types_p.h"
#include "radio_registry.h"
void
radio_registry_instance_added(
RadioInstance* instance)
- G_GNUC_INTERNAL;
+ RADIO_INTERNAL;
void
radio_registry_instance_removed(
const char* key)
- G_GNUC_INTERNAL;
+ RADIO_INTERNAL;
#endif /* RADIO_REGISTRY_PRIVATE_H */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/src/radio_request.c
^
|
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2021-2022 Jolla Ltd.
+ * Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#include "radio_base.h"
+#include "radio_request_p.h"
+#include "radio_request_group_p.h"
+#include "radio_log.h"
+
+#include <gbinder_local_request.h>
+#include <gbinder_writer.h>
+
+#include <gutil_macros.h>
+
+typedef enum radio_request_flags {
+ RADIO_REQUEST_NO_FLAGS = 0,
+ RADIO_REQUEST_FLAG_DROPPED = 0x01,
+ RADIO_REQUEST_FLAG_SUBMITTED = 0x02
+} RADIO_REQUEST_FLAGS;
+
+typedef struct radio_request_object {
+ RadioRequest pub;
+ GDestroyNotify destroy;
+ gsize serial_offset;
+ RADIO_REQUEST_FLAGS flags;
+ gint refcount;
+} RadioRequestObject;
+
+static inline RadioRequestObject* radio_request_cast(RadioRequest* req)
+ { return req ? G_CAST(req, RadioRequestObject, pub) : NULL; }
+
+/*==========================================================================*
+ * Implementation
+ *==========================================================================*/
+
+static
+void
+radio_request_object_cancel(
+ RadioRequestObject* self)
+{
+ RadioRequest* req = &self->pub;
+
+ radio_base_cancel_request(req->object, req);
+ if (!(self->flags & RADIO_REQUEST_FLAG_DROPPED)) {
+ self->flags |= RADIO_REQUEST_FLAG_DROPPED;
+ radio_request_group_remove(req->group, req);
+ radio_base_request_dropped(req);
+ }
+ radio_base_unregister_request(req->object, req);
+}
+
+static
+void
+radio_request_free(
+ RadioRequestObject* self)
+{
+ RadioRequest* req = &self->pub;
+
+ GVERBOSE_("%u (%08x) %p", req->code, req->serial, req);
+ radio_request_object_cancel(self);
+
+ /* Don't invoke completion routine if the request was never submitted */
+ if (req->complete && (self->flags & RADIO_REQUEST_FLAG_SUBMITTED)) {
+ RadioRequestCompleteFunc complete = req->complete;
+
+ /* Request is being freed too early, before completion */
+ req->complete = NULL;
+ complete(req, RADIO_TX_STATUS_FAILED, RADIO_RESP_NONE,
+ RADIO_ERROR_NONE, NULL, req->user_data);
+ }
+ if (self->destroy) {
+ GDestroyNotify destroy = self->destroy;
+
+ self->destroy = NULL;
+ destroy(req->user_data);
+ }
+ gbinder_local_request_unref(req->args);
+ gutil_slice_free(self);
+}
+
+static
+void
+radio_request_object_unref(
+ RadioRequestObject* self)
+{
+ if (G_LIKELY(self)) {
+ GASSERT(self->refcount > 0);
+ if (g_atomic_int_dec_and_test(&self->refcount)) {
+ radio_request_free(self);
+ }
+ }
+}
+
+static
+gboolean
+radio_request_default_retry(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ void* user_data)
+{
+ if (status != RADIO_TX_STATUS_OK) {
+ GVERBOSE_("req %p %u (%08x) status %d", req, req->code, req->serial,
+ status);
+ return TRUE;
+ } else if (error != RADIO_ERROR_NONE) {
+ GVERBOSE_("req %p %u (%08x) error %d", req, req->code, req->serial,
+ error);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+static
+RadioRequest*
+radio_request_object_new(
+ RadioBase* base,
+ RadioRequestGroup* group,
+ RADIO_REQ code,
+ GBinderWriter* writer,
+ RadioRequestGenericCompleteFunc complete,
+ GDestroyNotify destroy,
+ void* user_data)
+{
+ RadioRequestObject* self = g_slice_new0(RadioRequestObject);
+ RadioRequest* req = &self->pub;
+ GBinderWriter tmp;
+
+ self->destroy = destroy;
+ g_atomic_int_set(&self->refcount, 1);
+
+ req->state = RADIO_REQUEST_STATE_NEW;
+ req->code = code;
+ req->complete = complete;
+ req->user_data = user_data;
+ req->retry = radio_request_default_retry;
+
+ /* Assign serial and add to the group */
+ radio_base_register_request(base, req);
+ radio_request_group_add(group, req);
+ GVERBOSE_("%u (%08x) %p group %p", req->code, req->serial, req, group);
+
+ /* Build the argument list */
+ if (!writer) writer = &tmp;
+ req->args = RADIO_BASE_GET_CLASS(base)->new_request(base, code);
+ gbinder_local_request_init_writer(req->args, writer);
+ self->serial_offset = gbinder_writer_bytes_written(writer);
+ gbinder_writer_append_int32(writer, req->serial);
+ return req;
+}
+
+/*==========================================================================*
+ * Internal API
+ *==========================================================================*/
+
+void
+radio_request_unref_func(
+ gpointer req)
+{
+ radio_request_object_unref(radio_request_cast(req));
+}
+
+void
+radio_request_update_serial(
+ RadioRequest* req,
+ guint32 serial)
+{
+ GBinderWriter writer;
+
+ gbinder_local_request_init_writer(req->args, &writer);
+ gbinder_writer_overwrite_int32(&writer,
+ radio_request_cast(req)->serial_offset, serial);
+}
+
+/*==========================================================================*
+ * API
+ *==========================================================================*/
+
+RadioRequest*
+radio_request_new(
+ RadioClient* client,
+ RADIO_REQ code,
+ GBinderWriter* writer, /* NULL if serial is the only arg */
+ RadioRequestCompleteFunc complete,
+ GDestroyNotify destroy,
+ void* user_data)
+{
+ return client ? radio_request_object_new(RADIO_BASE(client), NULL,
+ code, writer, (RadioRequestGenericCompleteFunc) complete,
+ destroy, user_data) : NULL;
+}
+
+RadioRequest*
+radio_request_new2(
+ RadioRequestGroup* group,
+ RADIO_REQ code,
+ GBinderWriter* writer, /* NULL if serial is the only arg */
+ RadioRequestCompleteFunc complete,
+ GDestroyNotify destroy,
+ void* user_data)
+{
+ return group ? radio_request_object_new(RADIO_BASE(group->client), group,
+ code, writer, (RadioRequestGenericCompleteFunc) complete,
+ destroy, user_data) : NULL;
+}
+
+RadioRequest*
+radio_config_request_new(
+ RadioConfig* config,
+ RADIO_CONFIG_REQ code,
+ GBinderWriter* writer, /* NULL if serial is the only arg */
+ RadioConfigRequestCompleteFunc complete,
+ GDestroyNotify destroy,
+ void* user_data) /* Since 1.4.6 */
+{
+ return config ? radio_request_object_new(RADIO_BASE(config), NULL,
+ code, writer, (RadioRequestGenericCompleteFunc) complete,
+ destroy, user_data) : NULL;
+}
+
+RadioRequest*
+radio_request_ref(
+ RadioRequest* req)
+{
+ RadioRequestObject* self = radio_request_cast(req);
+
+ if (G_LIKELY(self)) {
+ GASSERT(self->refcount > 0);
+ g_atomic_int_inc(&self->refcount);
+ }
+ return req;
+}
+
+void
+radio_request_unref(
+ RadioRequest* req)
+{
+ radio_request_object_unref(radio_request_cast(req));
+}
+
+void
+radio_request_set_blocking(
+ RadioRequest* req,
+ gboolean blocking)
+{
+ if (G_LIKELY(req)) {
+ req->blocking = blocking;
+ }
+}
+
+void
+radio_request_set_timeout(
+ RadioRequest* req,
+ guint ms)
+{
+ if (G_LIKELY(req) && req->timeout_ms != ms) {
+ RadioBase* base = req->object;
+
+ req->timeout_ms = ms;
+ if (base && req->state >= RADIO_REQUEST_STATE_QUEUED) {
+ const guint timeout = radio_base_timeout_ms(base, req);
+
+ req->deadline = g_get_monotonic_time() + MICROSEC(timeout);
+ radio_base_reset_timeout(base);
+ }
+ }
+}
+
+void
+radio_request_set_retry(
+ RadioRequest* req,
+ guint delay_ms, /* Delay before each retry, in milliseconds */
+ int max_count) /* Negative count to keep retrying indefinitely */
+{
+ if (G_LIKELY(req)) {
+ req->retry_delay_ms = delay_ms;
+ req->max_retries = max_count;
+ }
+}
+
+void
+radio_request_set_retry_func(
+ RadioRequest* req,
+ RadioRequestRetryFunc retry)
+{
+ if (G_LIKELY(req)) {
+ req->retry = retry ? retry : radio_request_default_retry;
+ }
+}
+
+gboolean
+radio_request_submit(
+ RadioRequest* req)
+{
+ if (req && req->object && radio_base_submit_request(req->object, req)) {
+ radio_request_cast(req)->flags |= RADIO_REQUEST_FLAG_SUBMITTED;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+gboolean
+radio_request_retry(
+ RadioRequest* req)
+{
+ return req && req->object && radio_base_retry_request(req->object, req);
+}
+
+void
+radio_request_cancel(
+ RadioRequest* req)
+{
+ RadioRequestObject* self = radio_request_cast(req);
+
+ if (G_LIKELY(self)) {
+ req->complete = NULL;
+ radio_request_object_cancel(self);
+ }
+}
+
+void
+radio_request_drop(
+ RadioRequest* req)
+{
+ RadioRequestObject* self = radio_request_cast(req);
+
+ if (G_LIKELY(self)) {
+ req->complete = NULL;
+ radio_request_object_cancel(self);
+ radio_request_object_unref(self);
+ }
+}
+
+void*
+radio_request_user_data(
+ RadioRequest* req) /* Since 1.4.11 */
+{
+ return G_LIKELY(req) ? req->user_data : NULL;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/src/radio_request_group.c
^
|
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2021-2022 Jolla Ltd.
+ * Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#include "radio_base.h"
+#include "radio_client.h"
+#include "radio_request_group_p.h"
+#include "radio_request_p.h"
+#include "radio_log.h"
+
+#include <gutil_macros.h>
+
+typedef struct radio_request_group_object {
+ RadioRequestGroup pub;
+ GHashTable* requests;
+ gint refcount;
+} RadioRequestGroupObject;
+
+static inline RadioRequestGroupObject*
+radio_request_group_cast(RadioRequestGroup* group)
+ { return group ? G_CAST(group, RadioRequestGroupObject, pub) : NULL; }
+
+/*==========================================================================*
+ * Implementation
+ *==========================================================================*/
+
+void
+radio_request_group_unlink_func(
+ gpointer req)
+{
+ ((RadioRequest*)req)->group = NULL;
+}
+
+static
+void
+radio_request_group_free(
+ RadioRequestGroupObject* self)
+{
+ RadioRequestGroup* group = &self->pub;
+
+ radio_base_unblock(RADIO_BASE(group->client), group);
+ g_hash_table_destroy(self->requests);
+ radio_client_unref(group->client);
+ gutil_slice_free(self);
+}
+
+/*==========================================================================*
+ * Internal API
+ *==========================================================================*/
+
+void
+radio_request_group_add(
+ RadioRequestGroup* group,
+ RadioRequest* req)
+{
+ RadioRequestGroupObject* self = radio_request_group_cast(group);
+
+ /* Request is never NULL but the group may be */
+ if (self) {
+ g_hash_table_insert(self->requests, req, req);
+ req->group = group;
+ }
+}
+
+void
+radio_request_group_remove(
+ RadioRequestGroup* group,
+ RadioRequest* req)
+{
+ RadioRequestGroupObject* self = radio_request_group_cast(group);
+
+ /* Request is never NULL but the group may be */
+ if (self) {
+ g_hash_table_remove(self->requests, req);
+ }
+}
+
+/*==========================================================================*
+ * API
+ *==========================================================================*/
+
+RadioRequestGroup*
+radio_request_group_new(
+ RadioClient* client)
+{
+ if (G_LIKELY(client)) {
+ RadioRequestGroupObject* self = g_slice_new0(RadioRequestGroupObject);
+ RadioRequestGroup* group = &self->pub;
+
+ group->client = radio_client_ref(client);
+ self->requests = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, radio_request_group_unlink_func);
+ g_atomic_int_set(&self->refcount, 1);
+ return group;
+ }
+ return NULL;
+}
+
+RadioRequestGroup*
+radio_request_group_ref(
+ RadioRequestGroup* group)
+{
+ RadioRequestGroupObject* self = radio_request_group_cast(group);
+
+ if (G_LIKELY(self)) {
+ GASSERT(self->refcount > 0);
+ g_atomic_int_inc(&self->refcount);
+ }
+ return group;
+}
+
+void
+radio_request_group_unref(
+ RadioRequestGroup* group)
+{
+ RadioRequestGroupObject* self = radio_request_group_cast(group);
+
+ if (G_LIKELY(self)) {
+ GASSERT(self->refcount > 0);
+ if (g_atomic_int_dec_and_test(&self->refcount)) {
+ radio_request_group_free(self);
+ }
+ }
+}
+
+void
+radio_request_group_cancel(
+ RadioRequestGroup* group)
+{
+ RadioRequestGroupObject* self = radio_request_group_cast(group);
+
+ if (G_LIKELY(self)) {
+ GHashTableIter it;
+ gpointer value;
+ GSList* list = NULL;
+ GSList* l;
+
+ /*
+ * Move requests to the list and temporarily reference them
+ * before invoking any callbacks.
+ */
+ g_hash_table_iter_init(&it, self->requests);
+ while (g_hash_table_iter_next(&it, NULL, &value)) {
+ list = g_slist_prepend(list, radio_request_ref(value));
+ g_hash_table_iter_remove(&it);
+ }
+
+ /*
+ * Actually cancel the requests. This invokes completion callbacks.
+ * The group is already empty at this point.
+ */
+ for (l = list; l; l = l->next) {
+ radio_request_cancel(l->data);
+ }
+
+ /* Release the temporary references */
+ g_slist_free_full(list, radio_request_unref_func);
+ }
+}
+
+RADIO_BLOCK
+radio_request_group_block_status(
+ RadioRequestGroup* group)
+{
+ return group ? radio_base_block_status(RADIO_BASE(group->client), group) :
+ RADIO_BLOCK_NONE;
+}
+
+RADIO_BLOCK
+radio_request_group_block(
+ RadioRequestGroup* group)
+{
+ return group ? radio_base_block(RADIO_BASE(group->client), group) :
+ RADIO_BLOCK_NONE;
+}
+
+void
+radio_request_group_unblock(
+ RadioRequestGroup* group)
+{
+ if (group) {
+ radio_base_unblock(RADIO_BASE(group->client), group);
+ }
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/src/radio_request_group_p.h
^
|
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 Jolla Ltd.
+ * Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#ifndef RADIO_REQUEST_GROUP_PRIVATE_H
+#define RADIO_REQUEST_GROUP_PRIVATE_H
+
+#include "radio_types_p.h"
+#include <radio_request_group.h>
+
+void
+radio_request_group_add(
+ RadioRequestGroup* group,
+ RadioRequest* req)
+ RADIO_INTERNAL;
+
+void
+radio_request_group_remove(
+ RadioRequestGroup* group,
+ RadioRequest* req)
+ RADIO_INTERNAL;
+
+#endif /* RADIO_REQUEST_GROUP_PRIVATE_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/src/radio_request_p.h
^
|
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2021-2022 Jolla Ltd.
+ * Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#ifndef RADIO_REQUEST_PRIVATE_H
+#define RADIO_REQUEST_PRIVATE_H
+
+#include "radio_types_p.h"
+#include "radio_request.h"
+
+/*
+ * Request lifecycle
+ * =================
+ *
+ * +=====+
+ * | NEW | ----------------------[cancel]------------+
+ * +=====+ |
+ * | |
+ * [submit] |
+ * | |
+ * | |
+ * +----> +---------------+ |
+ * | | | |
+ * | | (blocked) |
+ * | (unblocked) | |
+ * | | v v
+ * | | +========+ +===========+
+ * (retry) | | QUEUED | ----[cancel]----> | CANCELLED |
+ * | | +========+ +===========+
+ * | | | ^
+ * | | (unblocked) |
+ * | | | |
+ * | | +----------+ |
+ * | | | |
+ * | v v |
+ * | +-------------+ |
+ * | | submit | +========+ |
+ * | | request | ---(error)---> | FAILED | |
+ * | | transaction | +========+ |
+ * | +-------------+ ^ |
+ * | | | |
+ * | (ok) +---(error)---------+ |
+ * | | / |
+ * | v / |
+ * | +=========+ +=========+ |
+ * +--- | PENDING | ---(timeout)---> | TIMEOUT | |
+ * +=========+ +=========+ |
+ * | \ |
+ * | +----------------[cancel]------------+
+ * (response)
+ * |
+ * v
+ * +======+
+ * | DONE |
+ * +======+
+ *
+ * Timeout starts ticking when request enters the PENDING state.
+ * The library maintains an internal reference to the request in
+ * QUEUED and PENDING states.
+ */
+
+typedef enum radio_request_state {
+ RADIO_REQUEST_STATE_INVALID,
+ RADIO_REQUEST_STATE_NEW,
+ RADIO_REQUEST_STATE_QUEUED,
+ RADIO_REQUEST_STATE_PENDING,
+ /*
+ * Reorder states carefully or better don't reorder at all.
+ * States >= RADIO_REQUEST_STATE_FAILED are assumed to be
+ * terminal states in the state machine.
+ */
+ RADIO_REQUEST_STATE_FAILED,
+ RADIO_REQUEST_STATE_CANCELLED,
+ RADIO_REQUEST_STATE_TIMEOUT,
+ RADIO_REQUEST_STATE_DONE
+} RADIO_REQUEST_STATE;
+
+typedef
+void
+(*RadioRequestGenericCompleteFunc)(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ guint32 resp,
+ RADIO_ERROR error,
+ const GBinderReader* args,
+ gpointer user_data);
+
+struct radio_request {
+ RADIO_REQUEST_STATE state;
+ guint32 code;
+ GBinderLocalRequest* args;
+ RadioRequestGenericCompleteFunc complete;
+ RadioRequestRetryFunc retry;
+ void* user_data;
+ guint32 serial; /* Immutable, generated at creation time */
+ guint32 serial2; /* Mutable, used by the last transaction */
+ int max_retries; /* Negative = retry indefinitely */
+ int retry_count; /* Number of times we have already retried */
+ guint retry_delay_ms; /* Delay before each retry, in milliseconds */
+ guint timeout_ms; /* Timeout, in milliseconds (0 = default) */
+ gint64 deadline; /* Monotonic time, in microseconds */
+ gint64 scheduled; /* Monotonic time, in microseconds */
+ gulong tx_id; /* Id of the request transaction */
+ gboolean blocking; /* TRUE if this request blocks all others */
+ gboolean acked;
+ RadioBase* object; /* Not a reference */
+ RadioRequestGroup* group; /* Not a reference */
+ RadioRequest* queue_next;
+};
+
+void
+radio_request_unref_func(
+ gpointer req)
+ RADIO_INTERNAL;
+
+void
+radio_request_update_serial(
+ RadioRequest* req,
+ guint32 serial)
+ RADIO_INTERNAL;
+
+#endif /* RADIO_REQUEST_PRIVATE_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/src/radio_types_p.h
^
|
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2021-2022 Jolla Ltd.
+ * Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#ifndef RADIO_TYPES_PRIVATE_H
+#define RADIO_TYPES_PRIVATE_H
+
+#include <radio_types.h>
+
+typedef struct radio_base RadioBase;
+
+#define RADIO_INTERNAL G_GNUC_INTERNAL
+
+/* Miliseconds to microseconds */
+#define MICROSEC(ms) (((gint64)(ms)) * 1000)
+
+/* Preprocessor magic related to observers */
+G_STATIC_ASSERT(RADIO_OBSERVER_PRIORITY_LOWEST == 0);
+G_STATIC_ASSERT(RADIO_OBSERVER_PRIORITY_HIGHEST == 7);
+#define FOREACH_OBSERVER_PRIORITY(p) p(0) p(1) p(2) p(3) p(4) p(5) p(6) p(7)
+#define RADIO_OBSERVER_PRIORITY_INDEX(p) ((p) - RADIO_OBSERVER_PRIORITY_LOWEST)
+#define RADIO_OBSERVER_PRIORITY_COUNT \
+ (RADIO_OBSERVER_PRIORITY_INDEX(RADIO_OBSERVER_PRIORITY_HIGHEST) + 1)
+
+/*
+ * A special assert fatal in debug build and non-fatal in release.
+ * Marks truely unavoidable conditions.
+ */
+#ifdef DEBUG
+# define DEBUG_ASSERT(expr) g_assert(expr)
+#else
+# define DEBUG_ASSERT(expr)
+#endif
+
+#endif /* RADIO_TYPES_PRIVATE_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Changed |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/src/radio_util.c
^
|
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2018-2021 Jolla Ltd.
- * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
+ * Copyright (C) 2018-2022 Jolla Ltd.
+ * Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of the BSD license as follows:
*
@@ -34,11 +34,24 @@
* any official policies, either expressed or implied.
*/
-#include "radio_util.h"
+#include "radio_util_p.h"
#include "radio_log.h"
GLOG_MODULE_DEFINE("gbinder-radio");
+guint
+radio_observer_priority_index(
+ RADIO_OBSERVER_PRIORITY priority)
+{
+ if (priority < RADIO_OBSERVER_PRIORITY_LOWEST) {
+ return 0;
+ } else if (priority > RADIO_OBSERVER_PRIORITY_HIGHEST) {
+ return RADIO_OBSERVER_PRIORITY_COUNT - 1;
+ } else {
+ return priority - RADIO_OBSERVER_PRIORITY_LOWEST;
+ }
+}
+
const char*
radio_req_name(
RADIO_REQ req)
@@ -48,17 +61,20 @@
case RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT: return "responseAcknowledgement";
#define RADIO_REQ_(req,resp,Name,NAME) \
case RADIO_REQ_##NAME: return #Name;
+#define RADIO_REQ__(req,resp,Name,NAME,x) \
+ case RADIO_REQ_##NAME##x: return #Name #x;
RADIO_CALL_1_0(RADIO_REQ_)
RADIO_CALL_1_1(RADIO_REQ_)
RADIO_CALL_1_2(RADIO_REQ_)
RADIO_CALL_1_3(RADIO_REQ_)
- RADIO_CALL_1_4(RADIO_REQ_)
+ RADIO_CALL_1_4_(RADIO_REQ__)
+ RADIO_CALL_1_5_(RADIO_REQ__)
#undef RADIO_REQ_
+#undef RADIO_REQ__
case RADIO_REQ_START_NETWORK_SCAN_1_2: return "startNetworkScan_1_2";
case RADIO_REQ_SET_INDICATION_FILTER_1_2: return "setIndicationFilter_1_2";
case RADIO_REQ_SETUP_DATA_CALL_1_2: return "setupDataCall_1_2";
case RADIO_REQ_DEACTIVATE_DATA_CALL_1_2: return "deactivateDataCall_1_2";
- case RADIO_REQ_SETUP_DATA_CALL_1_4: return "setupDataCall_1_4";
case RADIO_REQ_SET_INITIAL_ATTACH_APN_1_4: return "setInitialAttachApn_1_4";
case RADIO_REQ_SET_DATA_PROFILE_1_4: return "setDataProfile_1_4";
case RADIO_REQ_ANY:
@@ -75,12 +91,16 @@
case RADIO_RESP_ACKNOWLEDGE_REQUEST: return "acknowledgeRequest";
#define RADIO_RESP_(req,resp,Name,NAME) \
case RADIO_RESP_##NAME: return #Name "Response";
+#define RADIO_RESP__(req,resp,Name,NAME,x) \
+ case RADIO_RESP_##NAME##x: return #Name "Response" #x;
RADIO_CALL_1_0(RADIO_RESP_)
RADIO_CALL_1_1(RADIO_RESP_)
RADIO_CALL_1_2(RADIO_RESP_)
RADIO_CALL_1_3(RADIO_RESP_)
- RADIO_CALL_1_4(RADIO_RESP_)
+ RADIO_CALL_1_4_(RADIO_RESP__)
+ RADIO_CALL_1_5_(RADIO_RESP__)
#undef RADIO_RESP_
+#undef RADIO_RESP__
case RADIO_RESP_GET_CELL_INFO_LIST_1_2:
return "getCellInfoListResponse_1_2";
case RADIO_RESP_GET_ICC_CARD_STATUS_1_2:
@@ -101,8 +121,12 @@
return "getIccCardStatusResponse_1_4";
case RADIO_RESP_GET_DATA_CALL_LIST_RESPONSE_1_4:
return "getDataCallListResponse_1_4";
- case RADIO_RESP_SETUP_DATA_CALL_RESPONSE_1_4:
- return "setupDataCallResponse_1_4";
+ case RADIO_RESP_GET_DATA_CALL_LIST_1_5:
+ return "getDataCallList_1_5";
+ case RADIO_RESP_GET_CELL_INFO_LIST_1_5:
+ return "getCellInfoListResponse_1_5";
+ case RADIO_RESP_GET_ICC_CARD_STATUS_1_5:
+ return "getIccCardStatus_1_5";
case RADIO_RESP_ANY:
break;
}
@@ -120,6 +144,7 @@
RADIO_EVENT_1_1(RADIO_IND_)
RADIO_EVENT_1_2(RADIO_IND_)
RADIO_EVENT_1_4(RADIO_IND_)
+ RADIO_EVENT_1_5(RADIO_IND_)
#undef RADIO_IND_
case RADIO_IND_ANY:
break;
@@ -143,29 +168,236 @@
RADIO_REQ req)
{
switch (req) {
-#define RADIO_REQ_(req,resp,Name,NAME) \
+#define RADIO_REQ_RESP_(req,resp,Name,NAME) \
case RADIO_REQ_##NAME: return RADIO_RESP_##NAME;
- RADIO_CALL_1_0(RADIO_REQ_)
- RADIO_CALL_1_1(RADIO_REQ_)
- RADIO_CALL_1_2(RADIO_REQ_)
- RADIO_CALL_1_3(RADIO_REQ_)
- RADIO_CALL_1_4(RADIO_REQ_)
-#undef RADIO_REQ_
- case RADIO_REQ_SET_RESPONSE_FUNCTIONS:
- case RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT:
- case RADIO_REQ_START_NETWORK_SCAN_1_2:
- case RADIO_REQ_SET_INDICATION_FILTER_1_2:
+#define RADIO_REQ_RESP__(req,resp,Name,NAME,x) \
+ case RADIO_REQ_##NAME##x: return RADIO_RESP_##NAME##x;
+ RADIO_CALL_1_0(RADIO_REQ_RESP_)
+ RADIO_CALL_1_1(RADIO_REQ_RESP_)
+ RADIO_CALL_1_2(RADIO_REQ_RESP_)
+ RADIO_CALL_1_3(RADIO_REQ_RESP_)
+ RADIO_CALL_1_4_(RADIO_REQ_RESP__)
+ RADIO_CALL_1_5_(RADIO_REQ_RESP__)
+#undef RADIO_REQ_RESP_
+#undef RADIO_REQ_RESP__
case RADIO_REQ_SETUP_DATA_CALL_1_2:
+ return RADIO_RESP_SETUP_DATA_CALL;
case RADIO_REQ_DEACTIVATE_DATA_CALL_1_2:
- case RADIO_REQ_SETUP_DATA_CALL_1_4:
+ return RADIO_RESP_DEACTIVATE_DATA_CALL;
+ case RADIO_REQ_START_NETWORK_SCAN_1_2:
+ return RADIO_RESP_START_NETWORK_SCAN;
case RADIO_REQ_SET_INITIAL_ATTACH_APN_1_4:
+ return RADIO_RESP_SET_INITIAL_ATTACH_APN;
case RADIO_REQ_SET_DATA_PROFILE_1_4:
+ return RADIO_RESP_SET_DATA_PROFILE;
+ case RADIO_REQ_SET_INDICATION_FILTER_1_2:
+ return RADIO_RESP_SET_INDICATION_FILTER;
+
+ /*
+ * All these still need to be listed here to ensure a compilation
+ * warnings when something gets added to RADIO_REQ enum.
+ */
+ case RADIO_REQ_SET_RESPONSE_FUNCTIONS:
+ case RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT:
case RADIO_REQ_ANY:
break;
}
return RADIO_RESP_NONE;
}
+/**
+ * And this is a version of radio_req_resp which takes IRadio interface
+ * version into account. This one is OK to use.
+ */
+RADIO_RESP
+radio_req_resp2(
+ RADIO_REQ req,
+ RADIO_INTERFACE iface) /* Since 1.4.5 */
+{
+ switch (req) {
+ /*
+ * Requests expecting a response from a previous version of the
+ * interface.
+ */
+ case RADIO_REQ_SETUP_DATA_CALL_1_2:
+ return RADIO_RESP_SETUP_DATA_CALL;
+ case RADIO_REQ_DEACTIVATE_DATA_CALL_1_2:
+ return RADIO_RESP_DEACTIVATE_DATA_CALL;
+ case RADIO_REQ_START_NETWORK_SCAN_1_2:
+ return RADIO_RESP_START_NETWORK_SCAN;
+ case RADIO_REQ_SET_INITIAL_ATTACH_APN_1_4:
+ return RADIO_RESP_SET_INITIAL_ATTACH_APN;
+ case RADIO_REQ_SET_DATA_PROFILE_1_4:
+ return RADIO_RESP_SET_DATA_PROFILE;
+ case RADIO_REQ_SET_INDICATION_FILTER_1_2:
+ /* case RADIO_REQ_SET_INDICATION_FILTER_1_5: */
+ return RADIO_RESP_SET_INDICATION_FILTER;
+
+ /*
+ * Requests which may receive a response from a higher version of
+ * the interface.
+ */
+
+ /*
+ * getIccCardStatus
+ * getIccCardStatusResponse
+ * getIccCardStatusResponse_1_2
+ * getIccCardStatusResponse_1_4
+ * getIccCardStatusResponse_1_5
+ * ...
+ */
+ case RADIO_REQ_GET_ICC_CARD_STATUS:
+ switch (iface) {
+ case RADIO_INTERFACE_1_0:
+ case RADIO_INTERFACE_1_1:
+ return RADIO_RESP_GET_ICC_CARD_STATUS;
+ case RADIO_INTERFACE_1_2:
+ case RADIO_INTERFACE_1_3:
+ return RADIO_RESP_GET_ICC_CARD_STATUS_1_2;
+ case RADIO_INTERFACE_1_4:
+ return RADIO_RESP_GET_ICC_CARD_STATUS_1_4;
+ case RADIO_INTERFACE_1_5:
+ return RADIO_RESP_GET_ICC_CARD_STATUS_1_5;
+ case RADIO_INTERFACE_NONE:
+ case RADIO_INTERFACE_COUNT:
+ break;
+ }
+ return RADIO_RESP_NONE;
+
+ /*
+ * getCellInfoList
+ * getCellInfoListResponse
+ * getCellInfoListResponse_1_2
+ * getCellInfoListResponse_1_4
+ * getCellInfoListResponse_1_5 <= the last one
+ * getCellInfoList_1_6
+ */
+ case RADIO_REQ_GET_CELL_INFO_LIST:
+ switch (iface) {
+ case RADIO_INTERFACE_1_0:
+ case RADIO_INTERFACE_1_1:
+ return RADIO_RESP_GET_CELL_INFO_LIST;
+ case RADIO_INTERFACE_1_2:
+ case RADIO_INTERFACE_1_3:
+ return RADIO_RESP_GET_CELL_INFO_LIST_1_2;
+ case RADIO_INTERFACE_1_4:
+ return RADIO_RESP_GET_CELL_INFO_LIST_1_4;
+ default:
+ return RADIO_RESP_GET_CELL_INFO_LIST_1_5;
+ case RADIO_INTERFACE_NONE:
+ break;
+ }
+ return RADIO_RESP_NONE;
+
+ /*
+ * getCurrentCalls
+ * getCurrentCallsResponse
+ * getCurrentCallsResponse_1_2 <= the last one
+ * getCurrentCalls_1_6
+ */
+ case RADIO_REQ_GET_CURRENT_CALLS:
+ switch (iface) {
+ case RADIO_INTERFACE_1_0:
+ case RADIO_INTERFACE_1_1:
+ return RADIO_RESP_GET_CURRENT_CALLS;
+ default: /* The last one */
+ return RADIO_RESP_GET_CURRENT_CALLS_1_2;
+ case RADIO_INTERFACE_NONE:
+ break;
+ }
+ return RADIO_RESP_NONE;
+
+ /*
+ * getSignalStrength
+ * getSignalStrengthResponse
+ * getSignalStrengthResponse_1_2 <= the last one
+ * getSignalStrength_1_4
+ */
+ case RADIO_REQ_GET_SIGNAL_STRENGTH:
+ switch (iface) {
+ case RADIO_INTERFACE_1_0:
+ case RADIO_INTERFACE_1_1:
+ return RADIO_RESP_GET_SIGNAL_STRENGTH;
+ default: /* The last one */
+ return RADIO_RESP_GET_SIGNAL_STRENGTH_1_2;
+ case RADIO_INTERFACE_NONE:
+ break;
+ }
+ return RADIO_RESP_NONE;
+
+ /*
+ * getVoiceRegistrationState
+ * getVoiceRegistrationStateResponse
+ * getVoiceRegistrationStateResponse_1_2 <= the last one
+ * getVoiceRegistrationState_1_5
+ */
+ case RADIO_REQ_GET_VOICE_REGISTRATION_STATE:
+ switch (iface) {
+ case RADIO_INTERFACE_1_0:
+ case RADIO_INTERFACE_1_1:
+ return RADIO_RESP_GET_VOICE_REGISTRATION_STATE;
+ default: /* The last one */
+ return RADIO_RESP_GET_VOICE_REGISTRATION_STATE_1_2;
+ case RADIO_INTERFACE_NONE:
+ break;
+ }
+ return RADIO_RESP_NONE;
+
+ /*
+ * getDataRegistrationState
+ * getDataRegistrationStateResponse
+ * getDataRegistrationStateResponse_1_2
+ * getDataRegistrationStateResponse_1_4 <= the last one
+ * getDataRegistrationState_1_5
+ */
+ case RADIO_REQ_GET_DATA_REGISTRATION_STATE:
+ switch (iface) {
+ case RADIO_INTERFACE_1_0:
+ case RADIO_INTERFACE_1_1:
+ return RADIO_RESP_GET_DATA_REGISTRATION_STATE;
+ case RADIO_INTERFACE_1_2:
+ case RADIO_INTERFACE_1_3:
+ return RADIO_RESP_GET_DATA_REGISTRATION_STATE_1_2;
+ default: /* The last one */
+ return RADIO_RESP_GET_DATA_REGISTRATION_STATE_1_4;
+ case RADIO_INTERFACE_NONE:
+ break;
+ }
+ return RADIO_RESP_NONE;
+
+ /*
+ * getDataCallList
+ * getDataCallListResponse
+ * getDataCallListResponse_1_4
+ * getDataCallListResponse_1_5 <= the last one
+ * getDataCallList_1_6
+ */
+ case RADIO_REQ_GET_DATA_CALL_LIST:
+ switch (iface) {
+ case RADIO_INTERFACE_1_0:
+ case RADIO_INTERFACE_1_1:
+ case RADIO_INTERFACE_1_2:
+ case RADIO_INTERFACE_1_3:
+ return RADIO_RESP_GET_DATA_CALL_LIST;
+ case RADIO_INTERFACE_1_4:
+ return RADIO_RESP_GET_DATA_CALL_LIST_1_4;
+ default: /* The last one */
+ return RADIO_RESP_GET_DATA_CALL_LIST_1_5;
+ case RADIO_INTERFACE_NONE:
+ break;
+ }
+ return RADIO_RESP_NONE;
+
+ default:
+ break;
+ }
+
+ /* Fallback */
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+ return radio_req_resp(req);
+ G_GNUC_END_IGNORE_DEPRECATIONS
+}
+
/*
* Local Variables:
* mode: C
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/src/radio_util_p.h
^
|
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021-2022 Jolla Ltd.
+ * Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#ifndef RADIO_UTIL_PRIVATE_H
+#define RADIO_UTIL_PRIVATE_H
+
+#include "radio_types_p.h"
+#include "radio_util.h"
+
+guint
+radio_observer_priority_index(
+ RADIO_OBSERVER_PRIORITY priority)
+ RADIO_INTERNAL;
+
+#endif /* RADIO_UTIL_PRIVATE_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/Makefile
^
|
@@ -0,0 +1,15 @@
+# -*- Mode: makefile-gmake -*-
+
+.PHONY: clean all
+
+all:
+%:
+ @$(MAKE) -C unit_client $*
+ @$(MAKE) -C unit_config $*
+ @$(MAKE) -C unit_instance $*
+ @$(MAKE) -C unit_registry $*
+ @$(MAKE) -C unit_util $*
+
+clean: unitclean
+ rm -f coverage/*.gcov
+ rm -fr coverage/report
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/common/Makefile
^
|
@@ -0,0 +1,216 @@
+# -*- Mode: makefile-gmake -*-
+
+.PHONY: clean cleaner unitclean all debug release coverage valgrind
+.PHONY: debug_lib release_lib coverage_lib
+.PHONY: test test_banner
+
+#
+# Real test makefile defines EXE (and possibly SRC) and includes this one.
+#
+
+ifndef EXE
+${error EXE not defined}
+endif
+
+SRC ?= $(EXE).c
+COMMON_SRC ?= \
+ test_gbinder_client.c \
+ test_gbinder_local_object.c \
+ test_gbinder_local_request.c \
+ test_gbinder_local_reply.c \
+ test_gbinder_reader_writer.c \
+ test_gbinder_remote_object.c \
+ test_gbinder_remote_request.c \
+ test_gbinder_remote_reply.c \
+ test_gbinder_servicemanager.c \
+ test_main.c
+
+#
+# Required packages
+#
+
+LINK_PKGS += libglibutil glib-2.0 gobject-2.0
+PKGS += $(LINK_PKGS) libgbinder
+
+#
+# Default target
+#
+
+all: debug release
+
+#
+# Directories
+#
+
+SRC_DIR = .
+LIB_DIR = ../..
+COMMON_DIR = ../common
+BUILD_DIR = build
+DEBUG_BUILD_DIR = $(BUILD_DIR)/debug
+RELEASE_BUILD_DIR = $(BUILD_DIR)/release
+COVERAGE_BUILD_DIR = $(BUILD_DIR)/coverage
+COMMON_BUILD_DIR = $(COMMON_DIR)/build
+COMMON_DEBUG_BUILD_DIR = $(COMMON_BUILD_DIR)/debug
+COMMON_RELEASE_BUILD_DIR = $(COMMON_BUILD_DIR)/release
+COMMON_COVERAGE_BUILD_DIR = $(COMMON_BUILD_DIR)/coverage
+
+#
+# Tools and flags
+#
+
+CC ?= $(CROSS_COMPILE)gcc
+LD = $(CC)
+WARNINGS += -Wall -Wno-deprecated-declarations
+INCLUDES += -I$(COMMON_DIR) -I$(LIB_DIR)/src -I$(LIB_DIR)/include
+BASE_FLAGS = -fPIC
+FULL_CFLAGS = $(BASE_FLAGS) $(CFLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) \
+ -MMD -MP $(shell pkg-config --cflags $(PKGS))
+FULL_LDFLAGS = $(BASE_FLAGS) $(LDFLAGS)
+LIBS = $(shell pkg-config --libs $(LINK_PKGS)) -lpthread
+QUIET_MAKE = make --no-print-directory
+DEBUG_FLAGS = -g
+RELEASE_FLAGS =
+COVERAGE_FLAGS = -g
+
+DEBUG_LDFLAGS = $(FULL_LDFLAGS) $(DEBUG_FLAGS)
+RELEASE_LDFLAGS = $(FULL_LDFLAGS) $(RELEASE_FLAGS)
+COVERAGE_LDFLAGS = $(FULL_LDFLAGS) $(COVERAGE_FLAGS) --coverage
+
+DEBUG_CFLAGS = $(FULL_CFLAGS) $(DEBUG_FLAGS) -DDEBUG
+RELEASE_CFLAGS = $(FULL_CFLAGS) $(RELEASE_FLAGS) -O2
+COVERAGE_CFLAGS = $(FULL_CFLAGS) $(COVERAGE_FLAGS) --coverage
+
+DEBUG_LIB_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_lib)
+RELEASE_LIB_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_lib)
+COVERAGE_LIB_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_coverage_lib)
+
+DEBUG_LIB = $(LIB_DIR)/$(DEBUG_LIB_FILE)
+RELEASE_LIB = $(LIB_DIR)/$(RELEASE_LIB_FILE)
+COVERAGE_LIB = $(LIB_DIR)/$(COVERAGE_LIB_FILE)
+
+DEBUG_LIBS = $(DEBUG_LIB) $(LIBS)
+RELEASE_LIBS = $(RELEASE_LIB) $(LIBS)
+COVERAGE_LIBS = $(COVERAGE_LIB) $(LIBS)
+
+#
+# Files
+#
+
+TEST_DEBUG_OBJS = $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
+TEST_RELEASE_OBJS = $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
+TEST_COVERAGE_OBJS = $(SRC:%.c=$(COVERAGE_BUILD_DIR)/%.o)
+COMMON_DEBUG_OBJS = $(COMMON_SRC:%.c=$(COMMON_DEBUG_BUILD_DIR)/%.o)
+COMMON_RELEASE_OBJS = $(COMMON_SRC:%.c=$(COMMON_RELEASE_BUILD_DIR)/%.o)
+COMMON_COVERAGE_OBJS = $(COMMON_SRC:%.c=$(COMMON_COVERAGE_BUILD_DIR)/%.o)
+DEBUG_OBJS = $(COMMON_DEBUG_OBJS) $(TEST_DEBUG_OBJS)
+RELEASE_OBJS = $(COMMON_RELEASE_OBJS) $(TEST_RELEASE_OBJS)
+COVERAGE_OBJS = $(COMMON_COVERAGE_OBJS) $(TEST_COVERAGE_OBJS)
+
+#
+# Dependencies
+#
+
+DEPS = $(DEBUG_OBJS:%.o=%.d) $(RELEASE_OBJS:%.o=%.d)
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(strip $(DEPS)),)
+-include $(DEPS)
+endif
+endif
+
+$(DEBUG_LIB): | debug_lib
+$(RELEASE_LIB): | release_lib
+$(COVERAGE_LIB): | coverage_lib
+
+$(TEST_DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
+$(TEST_RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
+$(TEST_COVERAGE_OBJS): | $(COVERAGE_BUILD_DIR)
+
+$(COMMON_DEBUG_OBJS): | $(COMMON_DEBUG_BUILD_DIR)
+$(COMMON_RELEASE_OBJS): | $(COMMON_RELEASE_BUILD_DIR)
+$(COMMON_COVERAGE_OBJS): | $(COMMON_COVERAGE_BUILD_DIR)
+
+#
+# Rules
+#
+
+DEBUG_EXE = $(DEBUG_BUILD_DIR)/$(EXE)
+RELEASE_EXE = $(RELEASE_BUILD_DIR)/$(EXE)
+COVERAGE_EXE = $(COVERAGE_BUILD_DIR)/$(EXE)
+
+debug: debug_lib $(DEBUG_EXE)
+
+release: release_lib $(RELEASE_EXE)
+
+coverage: coverage_lib $(COVERAGE_EXE)
+
+unitclean:
+ rm -f *~
+ rm -fr $(BUILD_DIR) $(COMMON_BUILD_DIR)
+
+clean: unitclean
+
+cleaner: unitclean
+ @make -C $(LIB_DIR) clean
+
+test_banner:
+ @echo "===========" $(EXE) "=========== "
+
+test: test_banner debug
+ @$(DEBUG_EXE)
+
+valgrind: test_banner debug
+ @G_DEBUG=gc-friendly G_SLICE=always-malloc valgrind --tool=memcheck --leak-check=full --show-possibly-lost=no $(DEBUG_EXE)
+
+$(DEBUG_BUILD_DIR):
+ mkdir -p $@
+
+$(RELEASE_BUILD_DIR):
+ mkdir -p $@
+
+$(COVERAGE_BUILD_DIR):
+ mkdir -p $@
+
+$(COMMON_DEBUG_BUILD_DIR):
+ mkdir -p $@
+
+$(COMMON_RELEASE_BUILD_DIR):
+ mkdir -p $@
+
+$(COMMON_COVERAGE_BUILD_DIR):
+ mkdir -p $@
+
+$(DEBUG_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
+ $(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
+
+$(RELEASE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
+ $(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
+
+$(COVERAGE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
+ $(CC) -c $(COVERAGE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
+
+$(COMMON_DEBUG_BUILD_DIR)/%.o : $(COMMON_DIR)/%.c
+ $(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
+
+$(COMMON_RELEASE_BUILD_DIR)/%.o : $(COMMON_DIR)/%.c
+ $(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
+
+$(COMMON_COVERAGE_BUILD_DIR)/%.o : $(COMMON_DIR)/%.c
+ $(CC) -c $(COVERAGE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
+
+$(DEBUG_EXE): $(DEBUG_LIB) $(DEBUG_OBJS)
+ $(LD) $(DEBUG_LDFLAGS) $(DEBUG_OBJS) $(DEBUG_LIBS) -o $@
+
+$(RELEASE_EXE): $(RELEASE_LIB) $(RELEASE_OBJS)
+ $(LD) $(RELEASE_LDFLAGS) $(RELEASE_OBJS) $(RELEASE_LIBS) -o $@
+
+$(COVERAGE_EXE): $(COVERAG_LIB) $(COVERAGE_OBJS)
+ $(LD) $(COVERAGE_LDFLAGS) $(COVERAGE_OBJS) $(COVERAGE_LIBS) -o $@
+
+debug_lib:
+ $(MAKE) -C $(LIB_DIR) $@
+
+release_lib:
+ $(MAKE) -C $(LIB_DIR) $@
+
+coverage_lib:
+ $(MAKE) -C $(LIB_DIR) $@
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/common/test_common.h
^
|
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2018-2022 Jolla Ltd.
+ * Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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 TEST_COMMON_H
+#define TEST_COMMON_H
+
+#include <radio_types.h>
+
+#define TEST_FLAG_DEBUG (0x01)
+typedef struct test_opt {
+ int flags;
+} TestOpt;
+
+/* Should be invoked after g_test_init */
+void
+test_init(
+ TestOpt* opt,
+ int argc,
+ char* argv[]);
+
+/* Run loop with a timeout */
+void
+test_run(
+ const TestOpt* opt,
+ GMainLoop* loop);
+
+/* Quits the event loop on the next iteration */
+void
+test_quit_later(
+ GMainLoop* loop);
+
+/* Quits the event loop after n iterations */
+void
+test_quit_later_n(
+ GMainLoop* loop,
+ guint n);
+
+#define TEST_TIMEOUT_SEC (20)
+#define TEST_TIMEOUT_MS (1000*TEST_TIMEOUT_SEC)
+
+/* Helper macros */
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+# define TEST_INT16_BYTES(v) \
+ (guint8)(v), (guint8)((v) >> 8)
+# define TEST_INT32_BYTES(v) \
+ (guint8)(v), (guint8)((v) >> 8), \
+ (guint8)((v) >> 16), (guint8)((v) >> 24)
+# define TEST_INT64_BYTES(v) \
+ (guint8)(v), (guint8)((v) >> 8), \
+ (guint8)((v) >> 16), (guint8)((v) >> 24), \
+ (guint8)(((guint64)(v)) >> 32), (guint8)(((guint64)(v)) >> 40), \
+ (guint8)(((guint64)(v)) >> 48), (guint8)(((guint64)(v)) >> 56)
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+# define TEST_INT16_BYTES(v) \
+ (guint8)((v) >> 8), (guint8)(v)
+# define TEST_INT32_BYTES(v) \
+ (guint8)((v) >> 24), (guint8)((v) >> 16), \
+ (guint8)((v) >> 8), (guint8)(v)
+# define TEST_INT64_BYTES(v) \
+ (guint8)(((guint64)(v)) >> 56), (guint8)(((guint64)(v)) >> 48), \
+ (guint8)(((guint64)(v)) >> 40), (guint8)(((guint64)(v)) >> 32), \
+ (guint8)((v) >> 24), (guint8)((v) >> 16), \
+ (guint8)((v) >> 8), (guint8)(v)
+#else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
+#error unknown ENDIAN type
+#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
+
+#define TEST_ARRAY_AND_COUNT(a) a, G_N_ELEMENTS(a)
+#define TEST_ARRAY_AND_SIZE(a) a, sizeof(a)
+
+#endif /* TEST_COMMON_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/common/test_gbinder.h
^
|
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2021-2022 Jolla Ltd.
+ * Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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 TEST_GBINDER_H
+#define TEST_GBINDER_H
+
+#include <gbinder.h>
+
+typedef struct test_gbinder_data TestGBinderData;
+
+/* test_gbinder_reader_writer.c */
+
+TestGBinderData*
+test_gbinder_data_new(
+ const char* iface);
+
+TestGBinderData*
+test_gbinder_data_ref(
+ TestGBinderData* data);
+
+void
+test_gbinder_data_unref(
+ TestGBinderData* data);
+
+void
+test_gbinder_data_add_int32(
+ TestGBinderData* data,
+ guint32 value);
+
+void
+test_gbinder_data_add_hidl_struct(
+ TestGBinderData* data,
+ const void* buf,
+ gsize size);
+
+void
+test_gbinder_data_init_reader(
+ TestGBinderData* data,
+ GBinderReader* reader);
+
+void
+test_gbinder_data_init_writer(
+ TestGBinderData* data,
+ GBinderWriter* writer);
+
+/* test_gbinder_local_request.c */
+
+GBinderLocalRequest*
+test_gbinder_local_request_new(
+ const char* iface);
+
+const char*
+test_gbinder_local_request_interface(
+ GBinderLocalRequest* local);
+
+TestGBinderData*
+test_gbinder_local_request_data(
+ GBinderLocalRequest* local);
+
+/* test_gbinder_local_reply.c */
+
+GBinderLocalReply*
+test_gbinder_local_reply_new(
+ void);
+
+TestGBinderData*
+test_gbinder_local_reply_data(
+ GBinderLocalReply* reply);
+
+/* test_gbinder_remote_request.c */
+
+GBinderRemoteRequest*
+test_gbinder_remote_request_new(
+ GBinderLocalRequest* req);
+
+/* test_gbinder_remote_reply.c */
+
+GBinderRemoteReply*
+test_gbinder_remote_reply_new(
+ GBinderLocalReply* reply);
+
+/* test_gbinder_local_object.c */
+
+GBinderLocalObject*
+test_gbinder_local_object_new(
+ const char* const* ifaces,
+ GBinderLocalTransactFunc txproc,
+ void* user_data);
+
+GBinderLocalReply*
+test_gbinder_local_object_handle_tx(
+ GBinderLocalObject* self,
+ GBinderRemoteRequest* req,
+ guint code,
+ guint flags,
+ int* status);
+
+/* test_gbinder_remote_object.c */
+
+GBinderRemoteObject*
+test_gbinder_remote_object_new(
+ GBinderLocalObject* local);
+
+void
+test_gbinder_remote_object_kill(
+ GBinderRemoteObject* remote);
+
+gboolean
+test_gbinder_remote_object_dead(
+ GBinderRemoteObject* remote);
+
+GBinderLocalObject*
+test_gbinder_remote_object_to_local(
+ GBinderRemoteObject* remote);
+
+/* test_gbinder_client.c */
+
+extern int test_gbinder_client_tx_fail_count;
+
+/* test_gbinder_servicemanager.c */
+
+GBinderRemoteObject*
+test_gbinder_servicemanager_new_service(
+ GBinderServiceManager* manager,
+ const char* name,
+ GBinderLocalObject* local);
+
+#endif /* TEST_GBINDER_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/common/test_gbinder_client.c
^
|
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) 2021-2022 Jolla Ltd.
+ * Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#include "test_gbinder.h"
+
+#include <gutil_log.h>
+
+#include <stdlib.h>
+
+typedef struct test_gbinder_client_tx {
+ GBinderClient* client;
+ guint32 code;
+ guint32 flags;
+ GBinderLocalRequest* req;
+ GBinderClientReplyFunc reply;
+ GDestroyNotify destroy;
+ void* user_data;
+} TestGBinderClientTx;
+
+typedef struct test_gbinder_client_iface_range {
+ char* iface;
+ GBytes* header;
+ guint32 last_code;
+} TestGBinderClientIfaceRange;
+
+struct gbinder_client {
+ guint32 refcount;
+ GBinderRemoteObject* remote;
+ TestGBinderClientIfaceRange* ranges;
+ guint nr;
+};
+
+int test_gbinder_client_tx_fail_count = 0;
+
+static
+void
+test_gbinder_client_free(
+ GBinderClient* self)
+{
+ guint i;
+
+ for (i = 0; i < self->nr; i++) {
+ TestGBinderClientIfaceRange* r = self->ranges + i;
+
+ g_bytes_unref(r->header);
+ g_free(r->iface);
+ }
+ g_free(self->ranges);
+ gbinder_remote_object_unref(self->remote);
+ g_free(self);
+}
+
+static
+void
+test_gbinder_client_init_range(
+ TestGBinderClientIfaceRange* r,
+ const GBinderClientIfaceInfo* info)
+{
+ r->header = g_bytes_new(info->iface, strlen(info->iface));
+ r->iface = g_strdup(info->iface);
+ r->last_code = info->last_code;
+}
+
+static
+int
+test_gbinder_client_sort_ranges(
+ const void* p1,
+ const void* p2)
+{
+ const TestGBinderClientIfaceRange* r1 = p1;
+ const TestGBinderClientIfaceRange* r2 = p2;
+
+ return (r1->last_code < r2->last_code) ? (-1) :
+ (r1->last_code > r2->last_code) ? 1 : 0;
+}
+
+static
+const TestGBinderClientIfaceRange*
+test_gbinder_client_find_range(
+ GBinderClient* self,
+ guint32 code)
+{
+ guint i;
+
+ for (i = 0; i < self->nr; i++) {
+ const TestGBinderClientIfaceRange* r = self->ranges + i;
+
+ if (r->last_code >= code) {
+ return r;
+ }
+ }
+ return NULL;
+}
+
+static
+GBinderRemoteReply*
+test_gbinder_client_transact(
+ GBinderClient* self,
+ guint32 code,
+ guint32 flags,
+ GBinderLocalRequest* req,
+ int* status)
+{
+ GBinderLocalObject* obj = test_gbinder_remote_object_to_local(self->remote);
+ GBinderRemoteRequest* remote_req = test_gbinder_remote_request_new(req);
+ GBinderLocalReply* reply = test_gbinder_local_object_handle_tx(obj,
+ remote_req, code, flags, status);
+ GBinderRemoteReply* remote_reply = test_gbinder_remote_reply_new(reply);
+
+ gbinder_remote_request_unref(remote_req);
+ gbinder_local_reply_unref(reply);
+ return remote_reply;
+}
+
+static
+GBinderRemoteReply*
+test_gbinder_client_transact_sync(
+ GBinderClient* self,
+ guint32 code,
+ guint32 flags,
+ GBinderLocalRequest* req,
+ int* status)
+{
+ GBinderRemoteReply* reply = NULL;
+
+ if (self) {
+ GBinderRemoteObject* obj = self->remote;
+
+ if (!test_gbinder_remote_object_dead(obj)) {
+ GBinderLocalRequest* tmp = NULL;
+
+ if (!req) {
+ const TestGBinderClientIfaceRange* r =
+ test_gbinder_client_find_range(self, code);
+
+ if (r) {
+ req = tmp = test_gbinder_local_request_new(r->iface);
+ }
+ }
+ if (req) {
+ reply = test_gbinder_client_transact(self, code, flags, req,
+ status);
+ }
+ gbinder_local_request_unref(tmp);
+ } else {
+ GDEBUG("Refusing to perform transaction with a dead object");
+ }
+ }
+ return reply;
+}
+
+static
+gboolean
+test_gbinder_client_tx_handle(
+ gpointer data)
+{
+ int status = -1;
+ TestGBinderClientTx* tx = data;
+ GBinderRemoteReply* reply = test_gbinder_client_transact
+ (tx->client, tx->code, tx->flags, tx->req, &status);
+
+ if (tx->reply) {
+ tx->reply(tx->client, reply, status, tx->user_data);
+ }
+ gbinder_remote_reply_unref(reply);
+ return G_SOURCE_REMOVE;
+}
+
+static
+void
+test_gbinder_client_tx_destroy(
+ gpointer data)
+{
+ TestGBinderClientTx* tx = data;
+
+ if (tx->destroy) {
+ tx->destroy(tx->user_data);
+ }
+ gbinder_local_request_unref(tx->req);
+ gbinder_client_unref(tx->client);
+ g_free(tx);
+}
+
+/*==========================================================================*
+ * libgbinder API
+ *==========================================================================*/
+
+GBinderClient*
+gbinder_client_new2(
+ GBinderRemoteObject* remote,
+ const GBinderClientIfaceInfo* ifaces,
+ gsize count)
+{
+ if (remote) {
+ GBinderClient* self = g_new0(GBinderClient, 1);
+
+ g_atomic_int_set(&self->refcount, 1);
+ self->remote = gbinder_remote_object_ref(remote);
+ if (count > 0) {
+ gsize i;
+
+ self->nr = count;
+ self->ranges = g_new(TestGBinderClientIfaceRange, self->nr);
+ for (i = 0; i < count; i++) {
+ test_gbinder_client_init_range(self->ranges + i, ifaces + i);
+ }
+ qsort(self->ranges, count, sizeof(TestGBinderClientIfaceRange),
+ test_gbinder_client_sort_ranges);
+ } else {
+ /* No interface info */
+ self->nr = 1;
+ self->ranges = g_new0(TestGBinderClientIfaceRange, 1);
+ self->ranges[0].last_code = UINT_MAX;
+ }
+ return self;
+ }
+ return NULL;
+}
+
+GBinderClient*
+gbinder_client_ref(
+ GBinderClient* self)
+{
+ if (self) {
+ g_assert_cmpint(self->refcount, > ,0);
+ g_atomic_int_inc(&self->refcount);
+ }
+ return self;
+}
+
+void
+gbinder_client_unref(
+ GBinderClient* self)
+{
+ if (self) {
+ g_assert_cmpint(self->refcount, > ,0);
+ if (g_atomic_int_dec_and_test(&self->refcount)) {
+ test_gbinder_client_free(self);
+ }
+ }
+}
+
+GBytes*
+gbinder_client_rpc_header(
+ GBinderClient* self,
+ guint32 code)
+{
+ if (self) {
+ const TestGBinderClientIfaceRange* r =
+ test_gbinder_client_find_range(self, code);
+
+ if (r) {
+ return r->header;
+ }
+ }
+ return NULL;
+}
+
+GBinderLocalRequest*
+gbinder_client_new_request2(
+ GBinderClient* self,
+ guint32 code)
+{
+ if (self) {
+ const TestGBinderClientIfaceRange* r =
+ test_gbinder_client_find_range(self, code);
+
+ if (r) {
+ return test_gbinder_local_request_new(r->iface);
+ }
+ }
+ return NULL;
+}
+
+GBinderRemoteReply*
+gbinder_client_transact_sync_reply(
+ GBinderClient* self,
+ guint32 code,
+ GBinderLocalRequest* req,
+ int* status)
+{
+ return test_gbinder_client_transact_sync(self, code, 0, req, status);
+}
+
+int
+gbinder_client_transact_sync_oneway(
+ GBinderClient* self,
+ guint32 code,
+ GBinderLocalRequest* req)
+{
+ int status = -1;
+
+ g_assert(!test_gbinder_client_transact_sync(self, code,
+ GBINDER_TX_FLAG_ONEWAY, req, &status));
+ return status;
+}
+
+gulong
+gbinder_client_transact(
+ GBinderClient* self,
+ guint32 code,
+ guint32 flags,
+ GBinderLocalRequest* req,
+ GBinderClientReplyFunc reply,
+ GDestroyNotify destroy,
+ void* user_data)
+{
+ gulong id = 0;
+
+ if (self) {
+ GBinderRemoteObject* obj = self->remote;
+
+ if (!test_gbinder_remote_object_dead(obj)) {
+ if (test_gbinder_client_tx_fail_count) {
+ if (test_gbinder_client_tx_fail_count > 0) {
+ test_gbinder_client_tx_fail_count--;
+ }
+ GDEBUG("Simulating transaction failure");
+ } else {
+ GBinderLocalRequest* tmp = NULL;
+
+ if (!req) {
+ const TestGBinderClientIfaceRange* r =
+ test_gbinder_client_find_range(self, code);
+
+ if (r) {
+ req = tmp = test_gbinder_local_request_new(r->iface);
+ }
+ }
+ if (req) {
+ TestGBinderClientTx* tx = g_new0(TestGBinderClientTx, 1);
+
+ tx->client = gbinder_client_ref(self);
+ tx->code = code;
+ tx->flags = flags;
+ tx->req = gbinder_local_request_ref(req);
+ tx->reply = reply;
+ tx->destroy = destroy;
+ tx->user_data = user_data;
+ id = g_idle_add_full(G_PRIORITY_DEFAULT,
+ test_gbinder_client_tx_handle, tx,
+ test_gbinder_client_tx_destroy);
+ }
+ gbinder_local_request_unref(tmp);
+ }
+ } else {
+ GDEBUG("Refusing to perform transaction with a dead object");
+ }
+ }
+ return id;
+}
+
+void
+gbinder_client_cancel(
+ GBinderClient* self,
+ gulong id)
+{
+ if (id) {
+ g_source_remove((guint)id);
+ }
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/common/test_gbinder_local_object.c
^
|
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2021 Jolla Ltd.
+ * Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#include "test_gbinder.h"
+
+#include <gutil_strv.h>
+
+struct gbinder_local_object {
+ guint32 refcount;
+ char** ifaces;
+ GBinderLocalTransactFunc txproc;
+ void* user_data;
+};
+
+static const char hidl_base_interface[] = "android.hidl.base@1.0::IBase";
+
+static
+void
+test_gbinder_local_object_free(
+ GBinderLocalObject* self)
+{
+ g_strfreev(self->ifaces);
+ g_free(self);
+}
+
+/*==========================================================================*
+ * Internal API
+ *==========================================================================*/
+
+GBinderLocalObject*
+test_gbinder_local_object_new(
+ const char* const* ifaces,
+ GBinderLocalTransactFunc txproc,
+ void* user_data)
+{
+ GBinderLocalObject* self = g_new0(GBinderLocalObject, 1);
+ guint i = 0, n = gutil_strv_length((char**)ifaces);
+ gboolean append_base_interface;
+
+ if (g_strcmp0(gutil_strv_last((char**)ifaces), hidl_base_interface)) {
+ append_base_interface = TRUE;
+ n++;
+ } else {
+ append_base_interface = FALSE;
+ }
+
+ self->ifaces = g_new(char*, n + 1);
+ if (ifaces) {
+ while (*ifaces) {
+ self->ifaces[i++] = g_strdup(*ifaces++);
+ }
+ }
+ if (append_base_interface) {
+ self->ifaces[i++] = g_strdup(hidl_base_interface);
+ }
+ self->ifaces[i] = NULL;
+ self->txproc = txproc;
+ self->user_data = user_data;
+ g_atomic_int_set(&self->refcount, 1);
+ return self;
+}
+
+GBinderLocalReply*
+test_gbinder_local_object_handle_tx(
+ GBinderLocalObject* self,
+ GBinderRemoteRequest* req,
+ guint code,
+ guint flags,
+ int* status)
+{
+ return (self && self->txproc) ?
+ self->txproc(self, req, code, flags, status, self->user_data) :
+ NULL;
+}
+
+/*==========================================================================*
+ * libgbinder API
+ *==========================================================================*/
+
+GBinderLocalObject*
+gbinder_local_object_ref(
+ GBinderLocalObject* self)
+{
+ if (self) {
+ g_assert_cmpint(self->refcount, > ,0);
+ g_atomic_int_inc(&self->refcount);
+ }
+ return self;
+}
+
+void
+gbinder_local_object_unref(
+ GBinderLocalObject* self)
+{
+ if (self) {
+ g_assert_cmpint(self->refcount, > ,0);
+ if (g_atomic_int_dec_and_test(&self->refcount)) {
+ test_gbinder_local_object_free(self);
+ }
+ }
+}
+
+void
+gbinder_local_object_drop(
+ GBinderLocalObject* self)
+{
+ if (self) {
+ self->txproc = NULL;
+ self->user_data = NULL;
+ gbinder_local_object_unref(self);
+ }
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/common/test_gbinder_local_reply.c
^
|
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2021 Jolla Ltd.
+ * Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#include "test_gbinder.h"
+
+struct gbinder_local_reply {
+ guint32 refcount;
+ TestGBinderData* data;
+ char* iface;
+};
+
+static
+void
+test_gbinder_local_reply_free(
+ GBinderLocalReply* self)
+{
+ test_gbinder_data_unref(self->data);
+ g_free(self->iface);
+ g_free(self);
+}
+
+/*==========================================================================*
+ * Internal API
+ *==========================================================================*/
+
+GBinderLocalReply*
+test_gbinder_local_reply_new(
+ void)
+{
+ GBinderLocalReply* self = g_new0(GBinderLocalReply, 1);
+
+ g_atomic_int_set(&self->refcount, 1);
+ self->data = test_gbinder_data_new(NULL);
+ return self;
+}
+
+TestGBinderData*
+test_gbinder_local_reply_data(
+ GBinderLocalReply* self)
+{
+ return self ? self->data : NULL;
+}
+
+/*==========================================================================*
+ * libgbinder API
+ *==========================================================================*/
+
+GBinderLocalReply*
+gbinder_local_reply_ref(
+ GBinderLocalReply* self)
+{
+ if (self) {
+ g_assert_cmpint(self->refcount, > ,0);
+ g_atomic_int_inc(&self->refcount);
+ }
+ return self;
+}
+
+void
+gbinder_local_reply_unref(
+ GBinderLocalReply* self)
+{
+ if (self) {
+ g_assert_cmpint(self->refcount, > ,0);
+ if (g_atomic_int_dec_and_test(&self->refcount)) {
+ test_gbinder_local_reply_free(self);
+ }
+ }
+}
+
+void
+gbinder_local_reply_init_writer(
+ GBinderLocalReply* self,
+ GBinderWriter* writer)
+{
+ test_gbinder_data_init_writer(self->data, writer);
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/common/test_gbinder_local_request.c
^
|
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2021 Jolla Ltd.
+ * Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#include "test_gbinder.h"
+
+struct gbinder_local_request {
+ guint32 refcount;
+ TestGBinderData* data;
+ char* iface;
+};
+
+static
+void
+test_gbinder_local_request_free(
+ GBinderLocalRequest* self)
+{
+ test_gbinder_data_unref(self->data);
+ g_free(self->iface);
+ g_free(self);
+}
+
+/*==========================================================================*
+ * Internal API
+ *==========================================================================*/
+
+GBinderLocalRequest*
+test_gbinder_local_request_new(
+ const char* iface)
+{
+ GBinderLocalRequest* self = g_new0(GBinderLocalRequest, 1);
+
+ g_assert(iface);
+ g_atomic_int_set(&self->refcount, 1);
+ self->data = test_gbinder_data_new(iface);
+ self->iface = g_strdup(iface);
+ return self;
+}
+
+const char*
+test_gbinder_local_request_interface(
+ GBinderLocalRequest* self)
+{
+ return self ? self->iface : NULL;
+}
+
+TestGBinderData*
+test_gbinder_local_request_data(
+ GBinderLocalRequest* self)
+{
+ return self ? self->data : NULL;
+}
+
+/*==========================================================================*
+ * libgbinder API
+ *==========================================================================*/
+
+GBinderLocalRequest*
+gbinder_local_request_ref(
+ GBinderLocalRequest* self)
+{
+ if (self) {
+ g_assert_cmpint(self->refcount, > ,0);
+ g_atomic_int_inc(&self->refcount);
+ }
+ return self;
+}
+
+void
+gbinder_local_request_unref(
+ GBinderLocalRequest* self)
+{
+ if (self) {
+ g_assert_cmpint(self->refcount, > ,0);
+ if (g_atomic_int_dec_and_test(&self->refcount)) {
+ test_gbinder_local_request_free(self);
+ }
+ }
+}
+
+void
+gbinder_local_request_init_writer(
+ GBinderLocalRequest* self,
+ GBinderWriter* writer)
+{
+ test_gbinder_data_init_writer(self->data, writer);
+}
+
+GBinderLocalRequest*
+gbinder_local_request_append_int32(
+ GBinderLocalRequest* self,
+ guint32 value)
+{
+ if (self) {
+ GBinderWriter writer;
+
+ test_gbinder_data_init_writer(self->data, &writer);
+ gbinder_writer_append_int32(&writer, value);
+ }
+ return self;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/common/test_gbinder_reader_writer.c
^
|
@@ -0,0 +1,488 @@
+/*
+ * Copyright (C) 2021 Jolla Ltd.
+ * Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#include "test_gbinder.h"
+
+#include <gutil_misc.h>
+#include <gutil_idlepool.h>
+
+typedef enum test_gbinder_data_type {
+ DATA_TYPE_BOOLEAN,
+ DATA_TYPE_INT32,
+ DATA_TYPE_BUFFER,
+ DATA_TYPE_LOCAL_OBJ
+} DATA_TYPE;
+
+typedef struct test_gbinder_data_item TestGBinderDataItem;
+struct test_gbinder_data_item {
+ TestGBinderDataItem* next;
+ DATA_TYPE type;
+ union {
+ gboolean b;
+ gint32 i32;
+ struct {
+ void* buf;
+ gsize size;
+ } blob;
+ GBinderLocalObject* obj;
+ } data;
+ void (*destroy)(TestGBinderDataItem*);
+};
+
+struct test_gbinder_data {
+ guint32 refcount;
+ TestGBinderDataItem* items;
+ GUtilIdlePool* pool;
+ char* iface;
+};
+
+typedef struct test_gbinder_reader {
+ TestGBinderDataItem* item;
+} TestGBinderReader;
+
+typedef struct test_gbinder_writer {
+ TestGBinderData* data;
+} TestGBinderWriter;
+
+static inline TestGBinderReader* test_gbinder_reader_cast(GBinderReader* reader)
+ { return (TestGBinderReader*)reader; }
+
+static inline TestGBinderWriter* test_gbinder_writer_cast(GBinderWriter* writer)
+ { return (TestGBinderWriter*)writer; }
+
+static
+void
+test_gbinder_data_item_destroy_local_obj(
+ TestGBinderDataItem* item)
+{
+ g_assert_cmpint(item->type, == ,DATA_TYPE_LOCAL_OBJ);
+ gbinder_local_object_unref(item->data.obj);
+}
+
+static
+void
+test_gbinder_data_item_destroy_buffer(
+ TestGBinderDataItem* item)
+{
+ g_assert_cmpint(item->type, == ,DATA_TYPE_BUFFER);
+ g_free(item->data.blob.buf);
+}
+
+static
+TestGBinderDataItem*
+test_gbinder_data_item_new(
+ DATA_TYPE type)
+{
+ TestGBinderDataItem* item = g_new0(TestGBinderDataItem, 1);
+
+ item->type = type;
+ return item;
+}
+
+static
+void
+test_gbinder_data_item_free(
+ TestGBinderDataItem* item)
+{
+ if (item) {
+ test_gbinder_data_item_free(item->next);
+ if (item->destroy) {
+ item->destroy(item);
+ }
+ g_free(item);
+ }
+}
+
+static
+void
+test_gbinder_data_free(
+ TestGBinderData* data)
+{
+ test_gbinder_data_item_free(data->items);
+ gutil_idle_pool_destroy(data->pool);
+ g_free(data->iface);
+ g_free(data);
+}
+
+static
+guint
+test_gbinder_data_count_buffers(
+ TestGBinderData* data)
+{
+ TestGBinderDataItem* item;
+ guint n;
+
+ for (n = 0, item = data->items; item; item = item->next) {
+ if (item->type == DATA_TYPE_BUFFER) {
+ n++;
+ }
+ }
+ return n;
+}
+
+static
+void
+test_gbinder_data_append(
+ TestGBinderData* data,
+ TestGBinderDataItem* item)
+{
+ TestGBinderDataItem* last = data->items;
+
+ if (last) {
+ while (last->next) {
+ last = last->next;
+ }
+ last->next = item;
+ } else {
+ data->items = item;
+ }
+}
+
+static
+gsize
+test_gbinder_data_item_size(
+ TestGBinderDataItem* item)
+{
+ switch (item->type) {
+ case DATA_TYPE_BOOLEAN:
+ return sizeof(item->data.b);
+ case DATA_TYPE_INT32:
+ return sizeof(item->data.i32);
+ case DATA_TYPE_BUFFER:
+ return sizeof(item->data.blob);
+ case DATA_TYPE_LOCAL_OBJ:
+ return sizeof(item->data.obj);
+ }
+ return 0;
+}
+
+static
+void*
+test_gbinder_data_buffer(
+ TestGBinderData* data,
+ gsize* out_size)
+{
+ gsize size = 0;
+ void* ptr = NULL;
+
+ if (data) {
+ TestGBinderDataItem* item;
+ GByteArray* buf = g_byte_array_new();
+
+ if (data->iface) {
+ gsize header_size = strlen(data->iface);
+
+ g_byte_array_append(buf, (void*)data->iface, header_size);
+ size += header_size;
+ }
+ for (item = data->items; item; item = item->next) {
+ gsize item_size = test_gbinder_data_item_size(item);
+
+ g_byte_array_append(buf, (void*)&item->data, item_size);
+ size += item_size;
+ }
+ ptr = g_byte_array_free(buf, FALSE);
+ }
+ if (out_size) *out_size = size;
+ return ptr;
+}
+
+static
+gsize
+test_gbinder_data_size(
+ TestGBinderData* data)
+{
+ gsize size = 0;
+
+ if (data) {
+ TestGBinderDataItem* item;
+
+ if (data->iface) size += strlen(data->iface);
+ for (item = data->items; item; item = item->next) {
+ size += test_gbinder_data_item_size(item);
+ }
+ }
+ return size;
+}
+
+static
+guint32
+test_gbinder_date_replace_int32(
+ TestGBinderData* data,
+ gsize offset,
+ guint32 value)
+{
+ if (data) {
+ gsize size = 0;
+ TestGBinderDataItem* item;
+
+ if (data->iface) size += strlen(data->iface);
+ for (item = data->items; item; item = item->next) {
+ if (size == offset) {
+ guint32 prev;
+
+ g_assert_cmpint(item->type, == ,DATA_TYPE_INT32);
+ prev = item->data.i32;
+ item->data.i32 = value;
+ return prev;
+ }
+ size += test_gbinder_data_item_size(item);
+ }
+ }
+ return 0;
+}
+
+/*==========================================================================*
+ * Internal API
+ *==========================================================================*/
+
+TestGBinderData*
+test_gbinder_data_new(
+ const char* iface)
+{
+ TestGBinderData* data = g_new0(TestGBinderData, 1);
+
+ g_atomic_int_set(&data->refcount, 1);
+ data->iface = g_strdup(iface); /* Doubles as a request header */
+ return data;
+}
+
+TestGBinderData*
+test_gbinder_data_ref(
+ TestGBinderData* data)
+{
+ if (data) {
+ g_assert_cmpint(data->refcount, > ,0);
+ g_atomic_int_inc(&data->refcount);
+ }
+ return data;
+}
+
+void
+test_gbinder_data_unref(
+ TestGBinderData* data)
+{
+ if (data) {
+ g_assert_cmpint(data->refcount, > ,0);
+ if (g_atomic_int_dec_and_test(&data->refcount)) {
+ test_gbinder_data_free(data);
+ }
+ }
+}
+
+void
+test_gbinder_data_init_reader(
+ TestGBinderData* data,
+ GBinderReader* reader)
+{
+ memset(reader, 0, sizeof(*reader));
+ if (data) {
+ test_gbinder_reader_cast(reader)->item = data->items;
+ }
+}
+
+void
+test_gbinder_data_init_writer(
+ TestGBinderData* data,
+ GBinderWriter* writer)
+{
+ if (writer) {
+ memset(writer, 0, sizeof(*writer));
+ if (data) {
+ test_gbinder_writer_cast(writer)->data = data;
+ }
+ }
+}
+
+/*==========================================================================*
+ * libgbinder API
+ *==========================================================================*/
+
+gboolean
+gbinder_reader_read_uint32(
+ GBinderReader* reader,
+ guint32* value)
+{
+ TestGBinderReader* self = test_gbinder_reader_cast(reader);
+ TestGBinderDataItem* item = self->item;
+
+ if (item && item->type == DATA_TYPE_INT32) {
+ if (value) {
+ *value = item->data.i32;
+ }
+ self->item = item->next;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+gboolean
+gbinder_reader_read_int32(
+ GBinderReader* reader,
+ gint32* value)
+{
+ return gbinder_reader_read_uint32(reader, (guint32*)value);
+}
+
+const void*
+gbinder_reader_read_hidl_struct1(
+ GBinderReader* reader,
+ gsize size)
+{
+ TestGBinderReader* self = test_gbinder_reader_cast(reader);
+ TestGBinderDataItem* item = self->item;
+
+ if (item && item->type == DATA_TYPE_BUFFER &&
+ item->data.blob.size == size) {
+ self->item = item->next;
+ return item->data.blob.buf;
+ }
+ return NULL;
+}
+
+GBinderRemoteObject*
+gbinder_reader_read_object(
+ GBinderReader* reader)
+{
+ TestGBinderReader* self = test_gbinder_reader_cast(reader);
+ TestGBinderDataItem* item = self->item;
+
+ if (item && item->type == DATA_TYPE_LOCAL_OBJ) {
+ self->item = item->next;
+ return test_gbinder_remote_object_new(item->data.obj);
+ }
+ return NULL;
+}
+
+const void*
+gbinder_writer_get_data(
+ GBinderWriter* writer,
+ gsize* size)
+{
+ TestGBinderWriter* self = test_gbinder_writer_cast(writer);
+ TestGBinderData* data = self->data;
+ void* buf = test_gbinder_data_buffer(data, size);
+
+ if (buf) {
+ if (!data->pool) {
+ data->pool = gutil_idle_pool_new();
+ }
+ gutil_idle_pool_add(data->pool, buf, g_free);
+ }
+ return buf;
+}
+
+gsize
+gbinder_writer_bytes_written(
+ GBinderWriter* writer)
+{
+ TestGBinderWriter* self = test_gbinder_writer_cast(writer);
+
+ return test_gbinder_data_size(self->data);
+}
+
+void
+gbinder_writer_append_int32(
+ GBinderWriter* writer,
+ guint32 value)
+{
+ TestGBinderWriter* self = test_gbinder_writer_cast(writer);
+ TestGBinderDataItem* item = test_gbinder_data_item_new(DATA_TYPE_INT32);
+
+ item->data.i32 = value;
+ test_gbinder_data_append(self->data, item);
+}
+
+void
+gbinder_writer_overwrite_int32(
+ GBinderWriter* writer,
+ gsize offset,
+ gint32 value)
+{
+ TestGBinderWriter* self = test_gbinder_writer_cast(writer);
+
+ test_gbinder_date_replace_int32(self->data, offset, value);
+}
+
+void
+gbinder_writer_append_bool(
+ GBinderWriter* writer,
+ gboolean value)
+{
+ TestGBinderWriter* self = test_gbinder_writer_cast(writer);
+ TestGBinderDataItem* item = test_gbinder_data_item_new(DATA_TYPE_BOOLEAN);
+
+ item->data.b = value;
+ test_gbinder_data_append(self->data, item);
+}
+
+guint
+gbinder_writer_append_buffer_object(
+ GBinderWriter* writer,
+ const void* buf,
+ gsize size)
+{
+ TestGBinderWriter* self = test_gbinder_writer_cast(writer);
+ TestGBinderDataItem* item = test_gbinder_data_item_new(DATA_TYPE_BUFFER);
+ const guint index = test_gbinder_data_count_buffers(self->data);
+
+ item->destroy = test_gbinder_data_item_destroy_buffer;
+ item->data.blob.buf = gutil_memdup(buf, size);
+ item->data.blob.size = size;
+ test_gbinder_data_append(self->data, item);
+ return index;
+}
+
+void
+gbinder_writer_append_local_object(
+ GBinderWriter* writer,
+ GBinderLocalObject* obj)
+{
+ TestGBinderWriter* self = test_gbinder_writer_cast(writer);
+ TestGBinderDataItem* item = test_gbinder_data_item_new(DATA_TYPE_LOCAL_OBJ);
+
+ item->data.obj = gbinder_local_object_ref(obj);
+ item->destroy = test_gbinder_data_item_destroy_local_obj;
+ test_gbinder_data_append(self->data, item);
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/common/test_gbinder_remote_object.c
^
|
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2021 Jolla Ltd.
+ * Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#include "test_gbinder.h"
+
+#include <glib-object.h>
+
+struct gbinder_remote_object {
+ GObject parent;
+ GBinderLocalObject* local;
+ gboolean dead;
+};
+
+typedef GObjectClass GBinderRemoteObjectClass;
+G_DEFINE_TYPE(GBinderRemoteObject, gbinder_remote_object, G_TYPE_OBJECT)
+
+#define PARENT_CLASS gbinder_remote_object_parent_class
+#define THIS_TYPE (gbinder_remote_object_get_type())
+#define THIS(obj) G_TYPE_CHECK_INSTANCE_CAST(obj,THIS_TYPE,GBinderRemoteObject)
+
+enum gbinder_remote_object_signal {
+ SIGNAL_DEATH,
+ SIGNAL_COUNT
+};
+
+#define SIGNAL_DEATH_NAME "death"
+
+static guint remote_object_signals[SIGNAL_COUNT] = { 0 };
+
+static
+void
+gbinder_remote_object_init(
+ GBinderRemoteObject* self)
+{
+}
+
+static
+void
+gbinder_remote_object_finalize(
+ GObject* object)
+{
+ GBinderRemoteObject* self = THIS(object);
+
+ gbinder_local_object_unref(self->local);
+ G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
+}
+
+static
+void
+gbinder_remote_object_class_init(
+ GBinderRemoteObjectClass* klass)
+{
+ G_OBJECT_CLASS(klass)->finalize = gbinder_remote_object_finalize;
+ remote_object_signals[SIGNAL_DEATH] =
+ g_signal_new(SIGNAL_DEATH_NAME, G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
+}
+
+/*==========================================================================*
+ * Internal API
+ *==========================================================================*/
+
+GBinderRemoteObject*
+test_gbinder_remote_object_new(
+ GBinderLocalObject* local)
+{
+ GBinderRemoteObject* self = g_object_new(THIS_TYPE, NULL);
+
+ g_assert(local);
+ self->local = gbinder_local_object_ref(local);
+ return self;
+}
+
+void
+test_gbinder_remote_object_kill(
+ GBinderRemoteObject* self)
+{
+ if (self && !self->dead) {
+ self->dead = TRUE;
+ g_signal_emit(self, remote_object_signals[SIGNAL_DEATH], 0);
+ }
+}
+
+gboolean
+test_gbinder_remote_object_dead(
+ GBinderRemoteObject* self)
+{
+ return !self || self->dead;
+}
+
+GBinderLocalObject*
+test_gbinder_remote_object_to_local(
+ GBinderRemoteObject* self)
+{
+ return self ? self->local : NULL;
+}
+
+/*==========================================================================*
+ * libgbinder API
+ *==========================================================================*/
+
+GBinderRemoteObject*
+gbinder_remote_object_ref(
+ GBinderRemoteObject* self)
+{
+ if (self) {
+ g_object_ref(THIS(self));
+ }
+ return self;
+}
+
+void
+gbinder_remote_object_unref(
+ GBinderRemoteObject* self)
+{
+ if (self) {
+ g_object_unref(THIS(self));
+ }
+}
+
+gulong
+gbinder_remote_object_add_death_handler(
+ GBinderRemoteObject* self,
+ GBinderRemoteObjectNotifyFunc fn,
+ void* data)
+{
+ return (self && fn) ? g_signal_connect(self, SIGNAL_DEATH_NAME,
+ G_CALLBACK(fn), data) : 0;
+}
+
+void
+gbinder_remote_object_remove_handler(
+ GBinderRemoteObject* self,
+ gulong id)
+{
+ if (self && id) {
+ g_signal_handler_disconnect(self, id);
+ }
+}
+
+/*
+ * Remote Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/common/test_gbinder_remote_reply.c
^
|
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2021 Jolla Ltd.
+ * Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#include "test_gbinder.h"
+
+struct gbinder_remote_reply {
+ guint32 refcount;
+ TestGBinderData* data;
+};
+
+static
+void
+test_gbinder_remote_reply_free(
+ GBinderRemoteReply* self)
+{
+ test_gbinder_data_unref(self->data);
+ g_free(self);
+}
+
+/*==========================================================================*
+ * Internal API
+ *==========================================================================*/
+
+GBinderRemoteReply*
+test_gbinder_remote_reply_new(
+ GBinderLocalReply* reply)
+{
+ if (reply) {
+ GBinderRemoteReply* self = g_new0(GBinderRemoteReply, 1);
+ TestGBinderData* data = test_gbinder_local_reply_data(reply);
+
+ g_atomic_int_set(&self->refcount, 1);
+ self->data = test_gbinder_data_ref(data);
+ return self;
+ } else {
+ return NULL;
+ }
+}
+
+/*==========================================================================*
+ * libgbinder API
+ *==========================================================================*/
+
+GBinderRemoteReply*
+gbinder_remote_reply_ref(
+ GBinderRemoteReply* self)
+{
+ if (self) {
+ g_assert_cmpint(self->refcount, > ,0);
+ g_atomic_int_inc(&self->refcount);
+ }
+ return self;
+}
+
+void
+gbinder_remote_reply_unref(
+ GBinderRemoteReply* self)
+{
+ if (self) {
+ g_assert_cmpint(self->refcount, > ,0);
+ if (g_atomic_int_dec_and_test(&self->refcount)) {
+ test_gbinder_remote_reply_free(self);
+ }
+ }
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/common/test_gbinder_remote_request.c
^
|
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2021 Jolla Ltd.
+ * Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#include "test_gbinder.h"
+
+struct gbinder_remote_request {
+ guint32 refcount;
+ TestGBinderData* data;
+ char* iface;
+};
+
+static
+void
+test_gbinder_remote_request_free(
+ GBinderRemoteRequest* self)
+{
+ test_gbinder_data_unref(self->data);
+ g_free(self->iface);
+ g_free(self);
+}
+
+/*==========================================================================*
+ * Internal API
+ *==========================================================================*/
+
+GBinderRemoteRequest*
+test_gbinder_remote_request_new(
+ GBinderLocalRequest* req)
+{
+ GBinderRemoteRequest* self = g_new0(GBinderRemoteRequest, 1);
+
+ g_atomic_int_set(&self->refcount, 1);
+ self->data = test_gbinder_data_ref(test_gbinder_local_request_data(req));
+ self->iface = g_strdup(test_gbinder_local_request_interface(req));
+ return self;
+}
+
+/*==========================================================================*
+ * libgbinder API
+ *==========================================================================*/
+
+GBinderRemoteRequest*
+gbinder_remote_request_ref(
+ GBinderRemoteRequest* self)
+{
+ if (self) {
+ g_assert_cmpint(self->refcount, > ,0);
+ g_atomic_int_inc(&self->refcount);
+ }
+ return self;
+}
+
+void
+gbinder_remote_request_unref(
+ GBinderRemoteRequest* self)
+{
+ if (self) {
+ g_assert_cmpint(self->refcount, > ,0);
+ if (g_atomic_int_dec_and_test(&self->refcount)) {
+ test_gbinder_remote_request_free(self);
+ }
+ }
+}
+
+const char*
+gbinder_remote_request_interface(
+ GBinderRemoteRequest* self)
+{
+ return self ? self->iface : NULL;
+}
+
+void
+gbinder_remote_request_init_reader(
+ GBinderRemoteRequest* self,
+ GBinderReader* reader)
+{
+ test_gbinder_data_init_reader(self->data, reader);
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/common/test_gbinder_servicemanager.c
^
|
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2021 Jolla Ltd.
+ * Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#include "test_gbinder.h"
+
+#include <gutil_idlepool.h>
+#include <gutil_log.h>
+
+struct gbinder_servicemanager {
+ guint32 refcount;
+ GHashTable* services;
+ GUtilIdlePool* pool;
+ char* dev;
+};
+
+static GHashTable* test_servermanagers = NULL;
+
+static
+void
+test_gbinder_servicemanager_free(
+ GBinderServiceManager* self)
+{
+ /* Update the global table */
+ g_assert(test_servermanagers);
+ g_assert(g_hash_table_contains(test_servermanagers, self->dev));
+ g_hash_table_remove(test_servermanagers, self->dev); /* Frees self->dev */
+ if (g_hash_table_size(test_servermanagers) == 0) {
+ g_hash_table_unref(test_servermanagers);
+ test_servermanagers = NULL;
+ }
+
+ gutil_idle_pool_destroy(self->pool);
+ g_hash_table_destroy(self->services);
+ g_free(self);
+}
+
+/*==========================================================================*
+ * Internal API
+ *==========================================================================*/
+
+GBinderRemoteObject*
+test_gbinder_servicemanager_new_service(
+ GBinderServiceManager* self,
+ const char* name,
+ GBinderLocalObject* local)
+{
+ GBinderRemoteObject* remote = test_gbinder_remote_object_new(local);
+
+ g_hash_table_replace(self->services, g_strdup(name), remote);
+ return gbinder_remote_object_ref(remote);
+}
+
+/*==========================================================================*
+ * libgbinder API
+ *==========================================================================*/
+
+GBinderServiceManager*
+gbinder_servicemanager_new(
+ const char* dev)
+{
+ GBinderServiceManager* self = NULL;
+
+ g_assert(dev && dev[0]);
+ if (test_servermanagers) {
+ self = g_hash_table_lookup(test_servermanagers, dev);
+ }
+
+ if (self) {
+ gbinder_servicemanager_ref(self);
+ } else {
+ self = g_new0(GBinderServiceManager, 1);
+ g_atomic_int_set(&self->refcount, 1);
+ self->pool = gutil_idle_pool_new();
+ self->dev = g_strdup(dev); /* Owned by test_servermanagers */
+ self->services = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify) gbinder_remote_object_unref);
+
+ /* Update the global table */
+ if (!test_servermanagers) {
+ test_servermanagers = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, NULL);
+ }
+ g_hash_table_replace(test_servermanagers, self->dev, self);
+ }
+ return self;
+}
+
+GBinderServiceManager*
+gbinder_servicemanager_ref(
+ GBinderServiceManager* self)
+{
+ if (self) {
+ g_assert_cmpint(self->refcount, > ,0);
+ g_atomic_int_inc(&self->refcount);
+ }
+ return self;
+}
+
+void
+gbinder_servicemanager_unref(
+ GBinderServiceManager* self)
+{
+ if (self) {
+ g_assert_cmpint(self->refcount, > ,0);
+ if (g_atomic_int_dec_and_test(&self->refcount)) {
+ test_gbinder_servicemanager_free(self);
+ }
+ }
+}
+
+GBinderRemoteObject* /* autoreleased */
+gbinder_servicemanager_get_service_sync(
+ GBinderServiceManager* self,
+ const char* name,
+ int* status)
+{
+ if (self && name) {
+ GBinderRemoteObject* obj = g_hash_table_lookup(self->services, name);
+
+ if (obj) {
+ gutil_idle_pool_add(self->pool, gbinder_remote_object_ref(obj),
+ (GDestroyNotify) gbinder_remote_object_unref);
+ return obj;
+ } else {
+ GDEBUG("Name %s not found", name);
+ }
+ }
+ return NULL;
+}
+
+GBinderLocalObject*
+gbinder_servicemanager_new_local_object2(
+ GBinderServiceManager* self,
+ const char* const* ifaces,
+ GBinderLocalTransactFunc fn,
+ void* user_data)
+{
+ return self ? test_gbinder_local_object_new(ifaces, fn, user_data) : NULL;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/common/test_main.c
^
|
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2018-2021 Jolla Ltd.
+ * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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 "test_common.h"
+
+#include <gutil_log.h>
+
+typedef struct test_quit_later_data{
+ GMainLoop* loop;
+ guint n;
+} TestQuitLaterData;
+
+typedef struct test_context_data{
+ GMainLoop* loop;
+ GTestFunc func;
+} TestContextData;
+
+static
+gboolean
+test_timeout_expired(
+ gpointer data)
+{
+ g_assert(!"TIMEOUT");
+ return G_SOURCE_REMOVE;
+}
+
+static
+void
+test_quit_later_n_free(
+ gpointer user_data)
+{
+ TestQuitLaterData* data = user_data;
+
+ g_main_loop_unref(data->loop);
+ g_free(data);
+}
+
+static
+gboolean
+test_quit_later_n_func(
+ gpointer user_data)
+{
+ TestQuitLaterData* data = user_data;
+
+ if (data->n > 0) {
+ data->n--;
+ return G_SOURCE_CONTINUE;
+ } else {
+ g_main_loop_quit(data->loop);
+ return G_SOURCE_REMOVE;
+ }
+}
+
+void
+test_quit_later_n(
+ GMainLoop* loop,
+ guint n)
+{
+ TestQuitLaterData* data = g_new0(TestQuitLaterData, 1);
+
+ data->loop = g_main_loop_ref(loop);
+ data->n = n;
+ g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, test_quit_later_n_func, data,
+ test_quit_later_n_free);
+}
+
+static
+gboolean
+test_quit_later_cb(
+ gpointer data)
+{
+ g_main_loop_quit((GMainLoop*)data);
+ return G_SOURCE_REMOVE;
+}
+
+void
+test_quit_later(
+ GMainLoop* loop)
+{
+ g_idle_add(test_quit_later_cb, loop);
+}
+
+void
+test_run(
+ const TestOpt* opt,
+ GMainLoop* loop)
+{
+ if (opt->flags & TEST_FLAG_DEBUG) {
+ g_main_loop_run(loop);
+ } else {
+ const guint timeout_id = g_timeout_add_seconds(TEST_TIMEOUT_SEC,
+ test_timeout_expired, NULL);
+ g_main_loop_run(loop);
+ g_source_remove(timeout_id);
+ }
+}
+
+void
+test_init(
+ TestOpt* opt,
+ int argc,
+ char* argv[])
+{
+ const char* sep1;
+ const char* sep2;
+ int i;
+
+ memset(opt, 0, sizeof(*opt));
+ for (i=1; i<argc; i++) {
+ const char* arg = argv[i];
+ if (!strcmp(arg, "-d") || !strcmp(arg, "--debug")) {
+ opt->flags |= TEST_FLAG_DEBUG;
+ } else if (!strcmp(arg, "-v")) {
+ GTestConfig* config = (GTestConfig*)g_test_config_vars;
+ config->test_verbose = TRUE;
+ } else {
+ GWARN("Unsupported command line option %s", arg);
+ }
+ }
+
+ /* Setup logging */
+ sep1 = strrchr(argv[0], '/');
+ sep2 = strrchr(argv[0], '\\');
+ gutil_log_default.name = (sep1 && sep2) ? (MAX(sep1, sep2) + 1) :
+ sep1 ? (sep1 + 1) : sep2 ? (sep2 + 1) : argv[0];
+ gutil_log_default.level = g_test_verbose() ?
+ GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
+ gutil_log_timestamp = FALSE;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/coverage/run
^
|
@@ -0,0 +1,56 @@
+#!/bin/bash
+#
+# This script requires lcov, dirname
+#
+
+TESTS="\
+unit_client \
+unit_config \
+unit_instance \
+unit_registry \
+unit_util"
+
+function err() {
+ echo "*** ERROR!" $1
+ exit 1
+}
+
+# Check the required tools
+which lcov >> /dev/null || err "Please install lcov"
+which dirname >> /dev/null || err "Please install dirname"
+
+# LCOV 1.10 has branch coverage disabled per default
+# Previous versions didn't have the --rc option
+if [ ! -z "$(lcov --help | grep ' --rc ')" ] ; then
+ LCOV_OPT="--rc lcov_branch_coverage=1"
+ GENHTML_OPT="--branch-coverage"
+fi
+
+pushd `dirname $0` > /dev/null
+COV_DIR="$PWD"
+pushd .. > /dev/null
+TEST_DIR="$PWD"
+pushd .. > /dev/null
+TOP_DIR="$PWD"
+popd > /dev/null
+popd > /dev/null
+popd > /dev/null
+
+make -C "$TOP_DIR" clean
+for t in $TESTS ; do
+ pushd "$TEST_DIR/$t"
+ make -C "$TEST_DIR/$t" clean coverage || exit 1
+ build/coverage/$t || exit 1
+ popd
+done
+
+# Sometimes you need this, sometimes that :S
+BASE_DIR="$TOP_DIR"
+#BASE_DIR="$TOP_DIR/src"
+
+FULL_COV="$COV_DIR/full.gcov"
+LIB_COV="$COV_DIR/lib.gcov"
+rm -f "$FULL_COV" "$LIB_COV"
+lcov $LCOV_OPT -c -d "$TOP_DIR/build/coverage" -b "$BASE_DIR" -o "$FULL_COV" || exit 1
+lcov $LCOV_OPT -e "$FULL_COV" "$BASE_DIR/*" -o "$LIB_COV" || exit 1
+genhtml $GENHTML_OPT "$LIB_COV" -t "libgbinder-radio" --output-directory "$COV_DIR/report" || exit 1
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/unit_client/Makefile
^
|
@@ -0,0 +1,5 @@
+# -*- Mode: makefile-gmake -*-
+
+EXE = unit_client
+
+include ../common/Makefile
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/unit_client/unit_client.c
^
|
@@ -0,0 +1,2106 @@
+/*
+ * Copyright (C) 2021-2022 Jolla Ltd.
+ * Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#include "test_common.h"
+#include "test_gbinder.h"
+
+#include "radio_client.h"
+#include "radio_instance.h"
+#include "radio_request_p.h"
+#include "radio_request_group_p.h"
+#include "radio_util.h"
+
+#include <gutil_strv.h>
+#include <gutil_log.h>
+
+#define DEFAULT_INTERFACE RADIO_INTERFACE_1_0
+#define DEV GBINDER_DEFAULT_HWBINDER
+
+static TestOpt test_opt;
+
+static const GBinderClientIfaceInfo radio_ind_iface_info[] = {
+ {RADIO_INDICATION_1_4, RADIO_1_4_IND_LAST },
+ {RADIO_INDICATION_1_3, RADIO_1_3_IND_LAST },
+ {RADIO_INDICATION_1_2, RADIO_1_2_IND_LAST },
+ {RADIO_INDICATION_1_1, RADIO_1_1_IND_LAST },
+ {RADIO_INDICATION_1_0, RADIO_1_0_IND_LAST }
+};
+
+static const GBinderClientIfaceInfo radio_resp_iface_info[] = {
+ {RADIO_RESPONSE_1_4, RADIO_1_4_RESP_LAST },
+ {RADIO_RESPONSE_1_3, RADIO_1_3_RESP_LAST },
+ {RADIO_RESPONSE_1_2, RADIO_1_2_RESP_LAST },
+ {RADIO_RESPONSE_1_1, RADIO_1_1_RESP_LAST },
+ {RADIO_RESPONSE_1_0, RADIO_1_0_RESP_LAST }
+};
+
+static const char* const radio_req_ifaces[] = {
+ RADIO_1_4,
+ RADIO_1_3,
+ RADIO_1_2,
+ RADIO_1_1,
+ RADIO_1_0,
+ NULL
+};
+
+static
+void
+test_ind_not_reached(
+ RadioClient* client,
+ RADIO_IND code,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ g_assert_not_reached();
+}
+
+static
+void
+test_complete_not_reached(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ g_assert_not_reached();
+}
+
+static
+gboolean
+test_retry_not_reached(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ void* user_data)
+{
+ g_assert_not_reached();
+ return FALSE;
+}
+
+static
+void
+test_destroy_once(
+ gpointer user_data)
+{
+ gboolean* destroyed = user_data;
+
+ g_assert(!*destroyed);
+ *destroyed = TRUE;
+}
+
+static
+void
+test_inc_cb(
+ gpointer user_data)
+{
+ (*((int*)user_data))++;
+}
+
+static
+void
+test_client_inc_cb(
+ RadioClient* client,
+ gpointer user_data)
+{
+ (*((int*)user_data))++;
+}
+
+static
+gboolean
+test_unref_request_later(
+ gpointer user_data)
+{
+ radio_request_unref((RadioRequest*)user_data);
+ return G_SOURCE_REMOVE;
+}
+
+/*==========================================================================*
+ * Test IRadio service
+ *==========================================================================*/
+
+typedef struct test_radio_service {
+ GBinderLocalObject* obj;
+ GBinderClient* resp_client;
+ GBinderClient* ind_client;
+ GHashTable* req_count;
+ gboolean mute;
+} TestRadioService;
+
+#define FAIL_REQ RADIO_REQ_GET_ICC_CARD_STATUS
+#define ERROR_REQ RADIO_REQ_GET_IMS_REGISTRATION_STATE
+#define ERROR_RESP RADIO_RESP_GET_IMS_REGISTRATION_STATE
+#define IGNORE_REQ RADIO_REQ_GET_SIGNAL_STRENGTH
+
+static
+int
+test_service_req_count(
+ TestRadioService* service,
+ RADIO_REQ req)
+{
+ return GPOINTER_TO_INT(g_hash_table_lookup(service->req_count,
+ GINT_TO_POINTER(req)));
+}
+
+static
+GBinderLocalReply*
+test_service_txproc(
+ GBinderLocalObject* obj,
+ GBinderRemoteRequest* req,
+ guint code,
+ guint flags,
+ int* status,
+ void* user_data)
+{
+ TestRadioService* service = user_data;
+ const char* iface = gbinder_remote_request_interface(req);
+
+ if (gutil_strv_contains((const GStrV*)radio_req_ifaces, iface)) {
+ const int count = test_service_req_count(service, code) + 1;
+ GBinderReader reader;
+
+ GDEBUG("%s %s %d", iface, radio_req_name(code), count);
+ g_hash_table_insert(service->req_count, GINT_TO_POINTER(code),
+ GINT_TO_POINTER(count));
+
+ gbinder_remote_request_init_reader(req, &reader);
+ if (code == RADIO_REQ_SET_RESPONSE_FUNCTIONS) {
+ GBinderRemoteObject* resp_obj = gbinder_reader_read_object(&reader);
+ GBinderRemoteObject* ind_obj = gbinder_reader_read_object(&reader);
+
+ g_assert(resp_obj);
+ g_assert(ind_obj);
+ gbinder_client_unref(service->resp_client);
+ gbinder_client_unref(service->ind_client);
+ service->resp_client = gbinder_client_new2(resp_obj,
+ TEST_ARRAY_AND_COUNT(radio_resp_iface_info));
+ service->ind_client = gbinder_client_new2(ind_obj,
+ TEST_ARRAY_AND_COUNT(radio_ind_iface_info));
+ gbinder_remote_object_unref(resp_obj);
+ gbinder_remote_object_unref(ind_obj);
+ } else if (code == FAIL_REQ) {
+ GDEBUG("failing request transaction");
+ *status = GBINDER_STATUS_FAILED;
+ return NULL;
+ } else if (code == IGNORE_REQ) {
+ GDEBUG("ignoring request transaction");
+ } else if (code != RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT) {
+ RadioResponseInfo info;
+ GBinderWriter writer;
+ GBinderLocalRequest* resp = gbinder_client_new_request2
+ (service->resp_client, radio_req_resp(code));
+
+ memset(&info, 0, sizeof(info));
+ info.type = RADIO_RESP_SOLICITED;
+ info.error = (code == ERROR_REQ) ?
+ RADIO_ERROR_GENERIC_FAILURE :
+ RADIO_ERROR_NONE;
+ g_assert(gbinder_reader_read_uint32(&reader, &info.serial));
+
+ g_assert(resp);
+ gbinder_local_request_init_writer(resp, &writer);
+ gbinder_writer_append_buffer_object(&writer, &info, sizeof(info));
+
+ switch (code) {
+ case RADIO_REQ_GET_MUTE:
+ gbinder_writer_append_bool(&writer, service->mute);
+ g_assert(gbinder_client_transact(service->resp_client,
+ RADIO_RESP_GET_MUTE, GBINDER_TX_FLAG_ONEWAY,
+ resp, NULL, NULL, NULL));
+ break;
+ case RADIO_REQ_GET_IMS_REGISTRATION_STATE:
+ gbinder_writer_append_bool(&writer, FALSE);
+ g_assert(gbinder_client_transact(service->resp_client,
+ RADIO_RESP_GET_IMS_REGISTRATION_STATE,
+ GBINDER_TX_FLAG_ONEWAY, resp, NULL, NULL, NULL));
+ break;
+ default:
+ /* No expecting anything else */
+ g_assert_not_reached();
+ break;
+ }
+ gbinder_local_request_unref(resp);
+ }
+ *status = GBINDER_STATUS_OK;
+ return NULL;
+ } else {
+ GDEBUG("%s %u", iface, code);
+ *status = GBINDER_STATUS_FAILED;
+ return NULL;
+ }
+}
+
+static
+void
+test_service_init(
+ TestRadioService* service)
+{
+ memset(service, 0, sizeof(*service));
+ service->obj = test_gbinder_local_object_new(NULL,
+ test_service_txproc, service);
+ service->req_count = g_hash_table_new(g_direct_hash, g_direct_equal);
+}
+
+static
+void
+test_service_cleanup(
+ TestRadioService* service)
+{
+ g_hash_table_destroy(service->req_count);
+ gbinder_client_unref(service->resp_client);
+ gbinder_client_unref(service->ind_client);
+ gbinder_local_object_unref(service->obj);
+ memset(service, 0, sizeof(*service));
+}
+
+/*==========================================================================*
+ * Common setup for all tests
+ *==========================================================================*/
+
+typedef struct test_common {
+ TestRadioService service;
+ GBinderServiceManager* sm;
+ GBinderRemoteObject* remote;
+ RadioInstance* radio;
+ RadioClient* client;
+} TestCommon;
+
+static
+RadioClient*
+test_common_init(
+ TestCommon* test)
+{
+ memset(test, 0, sizeof(*test));
+ test->sm = gbinder_servicemanager_new(DEV);
+ test_service_init(&test->service);
+ test->remote = test_gbinder_servicemanager_new_service(test->sm,
+ RADIO_1_0 "/slot1", test->service.obj);
+ test->radio = radio_instance_new_with_version(DEV, "slot1",
+ RADIO_INTERFACE_1_0);
+ test->client = radio_client_new(test->radio);
+ g_assert(test->client);
+ return test->client;
+}
+
+static
+void
+test_common_connected(
+ TestCommon* test)
+{
+ const RADIO_IND ind = RADIO_IND_RIL_CONNECTED;
+ GBinderClient* ind_client = test->service.ind_client;
+ GBinderLocalRequest* req = gbinder_client_new_request2(ind_client, ind);
+
+ gbinder_local_request_append_int32(req, RADIO_IND_ACK_EXP);
+ g_assert_cmpint(gbinder_client_transact_sync_oneway(ind_client, ind, req),
+ == ,GBINDER_STATUS_OK);
+ gbinder_local_request_unref(req);
+ g_assert(radio_client_connected(test->client));
+}
+
+static
+void
+test_common_cleanup(
+ TestCommon* test)
+{
+ radio_client_unref(test->client);
+ radio_instance_unref(test->radio);
+ test_service_cleanup(&test->service);
+ gbinder_remote_object_unref(test->remote);
+ gbinder_servicemanager_unref(test->sm);
+}
+
+/*==========================================================================*
+ * Another common setup
+ *==========================================================================*/
+
+typedef struct test_simple_data {
+ TestCommon common;
+ GMainLoop* loop;
+ int completed; /* Typically used as a boolean */
+ int destroyed; /* Typically used as a boolean */
+} TestSimple;
+
+static
+RadioClient*
+test_simple_init(
+ TestSimple* test)
+{
+ memset(test, 0, sizeof(*test));
+ test->loop = g_main_loop_new(NULL, FALSE);
+ return test_common_init(&test->common);
+}
+
+static
+void
+test_simple_cleanup(
+ TestSimple* test)
+{
+ g_main_loop_unref(test->loop);
+ test_common_cleanup(&test->common);
+}
+
+static
+void
+test_simple_destroy_cb(
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ GDEBUG("done");
+ g_assert(test->completed);
+ g_assert(!test->destroyed);
+ test->destroyed = TRUE;
+ test_quit_later(test->loop);
+}
+
+static
+void
+test_simple_complete_ok_cb(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ GDEBUG("status %u", status);
+ g_assert_cmpint(status, == ,RADIO_TX_STATUS_OK);
+ g_assert_cmpint(error, == ,RADIO_ERROR_NONE);
+ g_assert(!test->completed);
+ g_assert(!test->destroyed);
+ test->completed = TRUE;
+}
+
+static
+void
+test_simple_complete_fail_cb(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ GDEBUG("status %u", status);
+ g_assert_cmpint(status, == ,RADIO_TX_STATUS_FAILED);
+ g_assert_cmpint(resp, == ,RADIO_RESP_NONE);
+ g_assert_cmpint(error, == ,RADIO_ERROR_NONE);
+ g_assert(!test->completed);
+ g_assert(!test->destroyed);
+ test->completed = TRUE;
+}
+
+static
+void
+test_simple_complete_error_cb(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ GDEBUG("error %d", error);
+ g_assert_cmpint(status, == ,RADIO_TX_STATUS_OK);
+ g_assert_cmpint(resp, == ,ERROR_RESP);
+ g_assert_cmpint(error, == ,RADIO_ERROR_GENERIC_FAILURE);
+ g_assert(!test->completed);
+ g_assert(!test->destroyed);
+ test->completed = TRUE;
+}
+
+/*==========================================================================*
+ * null
+ *==========================================================================*/
+
+static
+void
+test_null(
+ void)
+{
+ radio_client_unref(NULL);
+ radio_client_set_default_timeout(NULL, 0);
+ radio_client_remove_handler(NULL, 0);
+ radio_client_remove_handler(NULL, 1);
+ radio_client_remove_handlers(NULL, NULL, 0);
+
+ g_assert(!radio_client_new(NULL));
+ g_assert(!radio_client_ref(NULL));
+ g_assert(!radio_client_slot(NULL));
+ g_assert(!radio_client_connected(NULL));
+ g_assert(radio_client_dead(NULL));
+ g_assert(!radio_client_add_indication_handler(NULL, 0, NULL, NULL));
+ g_assert(!radio_client_add_owner_changed_handler(NULL, NULL, NULL));
+ g_assert(!radio_client_add_death_handler(NULL, NULL, NULL));
+ g_assert(!radio_client_add_connected_handler(NULL, NULL, NULL));
+ g_assert_cmpint(radio_client_interface(NULL), == ,RADIO_INTERFACE_NONE);
+
+ radio_request_unref(NULL);
+ radio_request_drop(NULL);
+ radio_request_cancel(NULL);
+ radio_request_set_blocking(NULL, FALSE);
+ radio_request_set_timeout(NULL, 0);
+ radio_request_set_retry(NULL, 0, 0);
+ radio_request_set_retry_func(NULL, NULL);
+
+ g_assert(!radio_request_new(NULL, 0, NULL, NULL, NULL, NULL));
+ g_assert(!radio_request_new2(NULL, 0, NULL, NULL, NULL, NULL));
+ g_assert(!radio_request_ref(NULL));
+ g_assert(!radio_request_submit(NULL));
+ g_assert(!radio_request_retry(NULL));
+ g_assert(!radio_request_user_data(NULL));
+
+ radio_request_group_cancel(NULL);
+ radio_request_group_unref(NULL);
+ radio_request_group_unblock(NULL);
+
+ g_assert(!radio_request_group_new(NULL));
+ g_assert(!radio_request_group_ref(NULL));
+ g_assert_cmpint(radio_request_group_block(NULL), ==, RADIO_BLOCK_NONE);
+ g_assert_cmpint(radio_request_group_block_status(NULL), ==,
+ RADIO_BLOCK_NONE);
+}
+
+/*==========================================================================*
+ * basic
+ *==========================================================================*/
+
+static
+void
+test_basic(
+ void)
+{
+ TestCommon test;
+ RadioRequest* req;
+ RadioClient* client = test_common_init(&test);
+ GBinderWriter args;
+ gboolean destroyed = FALSE;
+
+ g_assert_cmpstr(radio_client_slot(client), == ,test.radio->slot);
+ g_assert_cmpint(radio_client_interface(client), == , test.radio->version);
+ g_assert(!radio_client_connected(client));
+
+ /* Adding NULL handler is a nop */
+ g_assert(!radio_client_add_indication_handler(client, RADIO_IND_ANY,
+ NULL, NULL));
+ g_assert(!radio_client_add_owner_changed_handler(client, NULL, NULL));
+ g_assert(!radio_client_add_death_handler(client, NULL, NULL));
+ g_assert(!radio_client_add_connected_handler(client, NULL, NULL));
+
+ /* Create a request */
+ req = radio_request_new(client, RADIO_REQ_GET_MUTE, NULL, NULL, NULL, NULL);
+ g_assert(req);
+
+ /* Test ref/unref */
+ g_assert(radio_request_ref(req) == req);
+ g_assert(radio_client_ref(client) == client);
+ radio_client_unref(client);
+
+ /* These are OK to cancel more than once */
+ radio_request_cancel(req);
+ radio_request_cancel(req);
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_CANCELLED);
+ radio_request_drop(req); /* Matches radio_request_ref() above */
+ radio_request_drop(req); /* Releases the final ref */
+
+ /* Make sure destroy (but not completion) callback is invoked */
+ req = radio_request_new(client, RADIO_REQ_GET_MUTE, &args,
+ test_complete_not_reached, test_destroy_once, &destroyed);
+ g_assert(radio_request_user_data(req) == &destroyed);
+ radio_request_unref(req);
+ g_assert(destroyed);
+
+ /* Request survives the client but can't be submitted */
+ destroyed = FALSE;
+ req = radio_request_new(client, RADIO_REQ_GET_MUTE, NULL, NULL,
+ test_destroy_once, &destroyed);
+ radio_client_unref(client);
+ test.client = NULL;
+
+ g_assert(!destroyed);
+ g_assert(!radio_request_submit(req));
+ radio_request_set_timeout(req, 100); /* No effect, the client is gone */
+ radio_request_drop(req);
+
+ test_common_cleanup(&test);
+}
+
+/*==========================================================================*
+ * cancel
+ *==========================================================================*/
+
+static
+void
+test_cancel(
+ void)
+{
+ TestCommon test;
+ RadioRequest* req;
+ gboolean destroyed = FALSE;
+
+ test_common_init(&test);
+ req = radio_request_new(test.client, RADIO_REQ_GET_MUTE, NULL,
+ test_complete_not_reached, test_destroy_once, &destroyed);
+
+ g_assert(radio_request_submit(req));
+ radio_request_cancel(req);
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_CANCELLED);
+ radio_request_unref(req);
+
+ g_assert(destroyed);
+ test_common_cleanup(&test);
+}
+
+/*==========================================================================*
+ * cancelq
+ *==========================================================================*/
+
+static
+void
+test_cancel_queue(
+ void)
+{
+ TestCommon test;
+ RadioRequest* req[3];
+ gboolean destroyed[G_N_ELEMENTS(req)];
+ RadioRequestGroup* group = radio_request_group_new(test_common_init(&test));
+ guint i;
+
+ /* Make sure these requests get queued */
+ g_assert_cmpint(radio_request_group_block(group), ==,
+ RADIO_BLOCK_ACQUIRED);
+
+ for (i = 0; i < G_N_ELEMENTS(req); i++) {
+ destroyed[i] = FALSE;
+ req[i] = radio_request_new(test.client, RADIO_REQ_GET_MUTE, NULL,
+ test_complete_not_reached, test_destroy_once, destroyed + i);
+ g_assert(radio_request_submit(req[i]));
+ }
+
+ radio_request_cancel(req[0]);
+ radio_request_cancel(req[2]);
+ radio_request_cancel(req[1]);
+
+ for (i = 0; i < G_N_ELEMENTS(req); i++) {
+ g_assert_cmpint(req[i]->state, == ,RADIO_REQUEST_STATE_CANCELLED);
+ radio_request_unref(req[i]);
+ g_assert(destroyed[i]);
+ }
+
+ radio_request_group_unref(group);
+ test_common_cleanup(&test);
+}
+
+/*==========================================================================*
+ * ind
+ *==========================================================================*/
+
+typedef struct test_ind_data {
+ TestCommon common;
+ GMainLoop* loop;
+ RADIO_IND ind;
+ RADIO_IND ind2;
+} TestInd;
+
+static
+void
+test_ind_cb(
+ RadioClient* client,
+ RADIO_IND code,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestInd* test = user_data;
+
+ g_assert_cmpint(test->ind, == ,RADIO_IND_NONE);
+ g_assert_cmpint(code, == ,RADIO_IND_RIL_CONNECTED);
+ GDEBUG("%d", code);
+ test->ind = code;
+}
+
+static
+void
+test_ind_cb2(
+ RadioClient* client,
+ RADIO_IND code,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestInd* test = user_data;
+
+ g_assert_cmpint(test->ind2, == ,RADIO_IND_NONE);
+ g_assert_cmpint(code, == ,RADIO_IND_RIL_CONNECTED);
+ test->ind2 = code;
+ GDEBUG("%d (done)", code);
+ test_quit_later(test->loop);
+}
+
+static
+void
+test_ind(
+ void)
+{
+ GBinderLocalRequest* req;
+ GBinderClient* ind_client;
+ RadioClient* client;
+ TestInd test;
+ int connected = 0;
+ gulong id[4];
+
+ memset(&test, 0, sizeof(test));
+ test_common_init(&test.common);
+ test.loop = g_main_loop_new(NULL, FALSE);
+
+ client = test.common.client;
+ ind_client = test.common.service.ind_client;
+
+ /* Register and unregister one listener */
+ id[0] = radio_client_add_indication_handler(client, RADIO_IND_ANY,
+ test_ind_not_reached, NULL);
+ radio_client_remove_handler(client, id[0]);
+
+ /* Register actual listeners */
+ id[0] = radio_client_add_indication_handler(client, RADIO_IND_ANY,
+ test_ind_cb, &test);
+ id[1] = radio_client_add_indication_handler(client, RADIO_IND_RIL_CONNECTED,
+ test_ind_cb2, &test);
+ id[2] = radio_client_add_indication_handler(client,
+ RADIO_IND_CALL_STATE_CHANGED, test_ind_not_reached, NULL);
+ id[3] = radio_client_add_connected_handler(client,
+ test_client_inc_cb, &connected);
+
+ /* Submit the indication */
+ req = gbinder_client_new_request2(ind_client, RADIO_IND_RIL_CONNECTED);
+ gbinder_local_request_append_int32(req, RADIO_IND_ACK_EXP);
+ g_assert_cmpint(gbinder_client_transact(ind_client, RADIO_IND_RIL_CONNECTED,
+ GBINDER_TX_FLAG_ONEWAY, req, NULL, NULL, NULL), != ,0);
+ gbinder_local_request_unref(req);
+
+ /* And wait for test_ind_cb2 to terminate the loop */
+ test_run(&test_opt, test.loop);
+ g_assert_cmpint(test.ind, == ,RADIO_IND_RIL_CONNECTED);
+ g_assert_cmpint(test.ind2, == ,RADIO_IND_RIL_CONNECTED);
+ g_assert_cmpint(connected, == ,1);
+
+ /* Cleanup */
+ radio_client_remove_all_handlers(client, id);
+ g_main_loop_unref(test.loop);
+ test_common_cleanup(&test.common);
+}
+
+/*==========================================================================*
+ * resp
+ *==========================================================================*/
+
+static
+void
+test_resp_complete_cb(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ g_assert_cmpint(status, == ,RADIO_TX_STATUS_OK);
+ g_assert_cmpint(resp, == ,RADIO_RESP_GET_MUTE);
+ g_assert_cmpint(error, == ,RADIO_ERROR_NONE);
+ g_assert_cmpint(test->completed, <= ,test->destroyed);
+ test->completed++;
+ GDEBUG("resp %d %d", resp, test->completed);
+}
+
+static
+void
+test_resp_destroy_cb(
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ test->destroyed++;
+ g_assert_cmpint(test->completed, >= ,test->destroyed);
+ GDEBUG("destroy %d", test->destroyed);
+ if (test->destroyed == 2) {
+ GDEBUG("done");
+ test_quit_later(test->loop);
+ }
+}
+
+static
+void
+test_resp(
+ void)
+{
+ GBinderLocalRequest* ack;
+ GBinderLocalRequest* resp;
+ GBinderWriter writer;
+ RadioResponseInfo info;
+ TestSimple test;
+ RadioClient* client = test_simple_init(&test);
+ GBinderClient* resp_client = test.common.service.resp_client;
+ RadioRequest* req1 = radio_request_new(client, RADIO_REQ_GET_MUTE, NULL,
+ test_resp_complete_cb, test_resp_destroy_cb, &test);
+ RadioRequest* req2 = radio_request_new(client, RADIO_REQ_GET_MUTE, NULL,
+ test_resp_complete_cb, test_resp_destroy_cb, &test);
+
+ g_assert(req1);
+ g_assert(req2);
+ g_assert(req1->serial);
+ g_assert(req2->serial);
+ g_assert(radio_request_submit(req1));
+ g_assert(!radio_request_submit(req1)); /* Second time it fails */
+ radio_request_set_retry(req2, 0, -1); /* Won't actually be retried */
+ g_assert(radio_request_submit(req2));
+ test_common_connected(&test.common);
+
+ /* Ack the first one */
+ ack = gbinder_client_new_request2(resp_client,
+ RADIO_RESP_ACKNOWLEDGE_REQUEST);
+ gbinder_local_request_append_int32(ack, req1->serial);
+ g_assert_cmpint(gbinder_client_transact_sync_oneway(resp_client,
+ RADIO_RESP_ACKNOWLEDGE_REQUEST, ack), == ,GBINDER_STATUS_OK);
+ g_assert(req1->acked);
+
+ /* Release our refs */
+ radio_request_unref(req1);
+ radio_request_unref(req2);
+
+ test_run(&test_opt, test.loop);
+
+ g_assert_cmpint(test.completed, == ,2);
+ g_assert_cmpint(test.destroyed, == ,test.completed);
+
+ /* This ack is invalid and will be ignored */
+ g_assert_cmpint(gbinder_client_transact_sync_oneway(resp_client,
+ RADIO_RESP_ACKNOWLEDGE_REQUEST, ack), == ,GBINDER_STATUS_OK);
+ gbinder_local_request_unref(ack);
+
+ /* This response will be ignored */
+ memset(&info, 0, sizeof(info));
+ info.type = RADIO_RESP_SOLICITED;
+ info.serial = 123;
+
+ resp = gbinder_client_new_request2(resp_client, RADIO_RESP_GET_MUTE);
+ g_assert(resp);
+ gbinder_local_request_init_writer(resp, &writer);
+ gbinder_writer_append_buffer_object(&writer, &info, sizeof(info));
+ gbinder_writer_append_bool(&writer, test.common.service.mute);
+ g_assert_cmpint(gbinder_client_transact_sync_oneway(resp_client,
+ RADIO_RESP_GET_MUTE, resp), == ,GBINDER_STATUS_OK);
+ gbinder_local_request_unref(resp);
+
+ /* Cleanup */
+ test_simple_cleanup(&test);
+}
+
+/*==========================================================================*
+ * group
+ *==========================================================================*/
+
+static
+void
+test_group(
+ void)
+{
+ TestSimple test;
+ RadioRequest* req;
+ RadioClient* client = test_simple_init(&test);
+ RadioRequestGroup* group = radio_request_group_new(client);
+ RadioRequestGroup* group2;
+ gulong id;
+ int destroyed = 0;
+ int blocked = 0;
+
+ g_assert(group);
+ test_common_connected(&test.common);
+
+ /* Test ref/unref */
+ g_assert(radio_request_group_ref(group) == group);
+ radio_request_group_unref(group);
+
+ /* Block status */
+ g_assert_cmpint(radio_request_group_block_status(group), ==,
+ RADIO_BLOCK_NONE);
+ id = radio_client_add_owner_changed_handler(client,
+ test_client_inc_cb, &blocked);
+ g_assert(id);
+ g_assert_cmpint(radio_request_group_block(group), ==,
+ RADIO_BLOCK_ACQUIRED);
+ g_assert_cmpint(blocked, == ,1);
+ g_assert_cmpint(radio_request_group_block(group), ==,
+ RADIO_BLOCK_ACQUIRED);
+ g_assert_cmpint(blocked, == ,1);
+ g_assert_cmpint(radio_request_group_block_status(group), ==,
+ RADIO_BLOCK_ACQUIRED);
+
+ /* Second group can't become an owner */
+ group2 = radio_request_group_new(client);
+ g_assert(group2);
+ g_assert_cmpint(radio_request_group_block(group2), ==,
+ RADIO_BLOCK_QUEUED);
+ g_assert_cmpint(radio_request_group_block(group2), ==,
+ RADIO_BLOCK_QUEUED);
+ g_assert_cmpint(blocked, == ,1);
+ g_assert_cmpint(radio_request_group_block_status(group2), ==,
+ RADIO_BLOCK_QUEUED);
+ radio_request_group_unref(group2);
+
+ /* Create two requests */
+ req = radio_request_new2(group, RADIO_REQ_GET_MUTE, NULL,
+ test_complete_not_reached, test_inc_cb, &destroyed);
+ g_assert(req);
+ g_assert(radio_request_submit(req));
+ radio_request_unref(req);
+
+ req = radio_request_new2(group, RADIO_REQ_GET_MUTE, NULL,
+ test_complete_not_reached, test_inc_cb, &destroyed);
+ g_assert(req);
+ g_assert(radio_request_submit(req));
+ radio_request_unref(req);
+
+ /* Create a request without a group */
+ req = radio_request_new(client, RADIO_REQ_GET_MUTE, NULL,
+ test_simple_complete_ok_cb, test_simple_destroy_cb, &test);
+
+ /* It can't be submitted right away because client is owned by group */
+ GDEBUG("Submitting a standalone request");
+ g_assert(radio_request_submit(req));
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_QUEUED);
+ radio_request_unref(req);
+
+ /* Cancel the whole group in one shot */
+ g_assert(!destroyed);
+ GDEBUG("Cancelling group");
+ radio_request_group_cancel(group);
+ g_assert_cmpint(destroyed, == ,2);
+
+ /* Cancel another one explicitly */
+ req = radio_request_new2(group, RADIO_REQ_GET_MUTE, NULL,
+ test_complete_not_reached, test_inc_cb, &destroyed);
+ g_assert(req);
+ radio_request_cancel(req);
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_CANCELLED);
+ radio_request_unref(req);
+ g_assert_cmpint(destroyed, == ,3);
+
+ /*
+ * Unblocking the group will allow the group-less request to get
+ * actually submitted, complete and quit the loop.
+ */
+ GDEBUG("Unblocking");
+ radio_request_group_unblock(group);
+ test_run(&test_opt, test.loop);
+
+ /* Cleanup */
+ radio_request_group_unref(group);
+ test_simple_cleanup(&test);
+}
+
+/*==========================================================================*
+ * group2
+ *==========================================================================*/
+
+static
+void
+test_group2(
+ void)
+{
+ TestCommon test;
+ RadioRequest* req;
+ RadioRequestGroup* group;
+ gulong id;
+ int destroyed = 0;
+ int blocked = 0;
+
+ test_common_init(&test);
+ test_common_connected(&test);
+
+ group = radio_request_group_new(test.client);
+ g_assert(group);
+
+ /* Submit a request */
+ req = radio_request_new2(group, RADIO_REQ_GET_MUTE, NULL,
+ test_complete_not_reached, test_inc_cb, &destroyed);
+ g_assert(req);
+ g_assert(radio_request_submit(req));
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_PENDING);
+
+ /* The group immediately becomes an owner because the pending
+ * request is associated with it */
+ g_assert_cmpint(radio_request_group_block_status(group), ==,
+ RADIO_BLOCK_NONE);
+ id = radio_client_add_owner_changed_handler(test.client,
+ test_client_inc_cb, &blocked);
+ g_assert(id);
+ g_assert_cmpint(radio_request_group_block(group), ==,
+ RADIO_BLOCK_ACQUIRED);
+ g_assert_cmpint(blocked, == ,1);
+
+ /* Destroying the group drops the ownership */
+ radio_request_group_unref(group);
+ g_assert_cmpint(blocked, == ,2);
+ g_assert(!destroyed);
+
+ /* Cancel the request */
+ radio_request_cancel(req);
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_CANCELLED);
+ radio_request_unref(req);
+ g_assert_cmpint(destroyed, == ,1);
+
+ /* Cleanup */
+ test_common_cleanup(&test);
+}
+
+/*==========================================================================*
+ * group3
+ *==========================================================================*/
+
+typedef struct test_group3_data {
+ TestCommon common;
+ GMainLoop* loop;
+ int completed;
+ int destroyed;
+} TestGroup3;
+
+static
+void
+test_group3_complete_cb(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestGroup3* test = user_data;
+
+ g_assert_cmpint(status, == ,RADIO_TX_STATUS_OK);
+ g_assert_cmpint(resp, == ,RADIO_RESP_GET_MUTE);
+ g_assert_cmpint(error, == ,RADIO_ERROR_NONE);
+ g_assert(!test->completed);
+ g_assert(!test->destroyed);
+ g_assert(!req->group);
+ test->completed++;
+ GDEBUG("completion %d", test->completed);
+}
+
+static
+void
+test_group3_complete2_cb(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestGroup3* test = user_data;
+
+ g_assert_cmpint(status, == ,RADIO_TX_STATUS_OK);
+ g_assert_cmpint(resp, == ,RADIO_RESP_GET_MUTE);
+ g_assert_cmpint(error, == ,RADIO_ERROR_NONE);
+ g_assert(req->group);
+ test->completed++;
+ GDEBUG("completion %d", test->completed);
+}
+
+static
+void
+test_group3_destroy_continue_cb(
+ gpointer user_data)
+{
+ TestGroup3* test = user_data;
+
+ test->destroyed++;
+ g_assert_cmpint(test->destroyed, == ,test->completed);
+ GDEBUG("destruction %d", test->destroyed);
+ test_quit_later(test->loop);
+}
+
+static
+void
+test_group3(
+ void)
+{
+ TestGroup3 test;
+ RadioRequest* req;
+ RadioRequest* req1;
+ RadioRequest* req2;
+ RadioRequest* req3;
+ RadioRequestGroup* group1;
+ RadioRequestGroup* group2;
+ RadioRequestGroup* group3;
+ RadioClient* client;
+ int owner_changed = 0;
+ gulong id;
+
+ memset(&test, 0, sizeof(test));
+ test_common_init(&test.common);
+ test_common_connected(&test.common);
+ test.loop = g_main_loop_new(NULL, FALSE);
+ client = test.common.client;
+
+ group1 = radio_request_group_new(client);
+ g_assert(group1);
+
+ /* This one will prevent the group from immediately becoming the owner */
+ req = radio_request_new(client, RADIO_REQ_GET_MUTE, NULL,
+ test_group3_complete_cb, test_group3_destroy_continue_cb, &test);
+ g_assert(req);
+ g_assert(radio_request_submit(req));
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_PENDING);
+ radio_request_unref(req);
+
+ /* No group can become the owner until pending request gets completed */
+ g_assert_cmpint(radio_request_group_block_status(group1), ==,
+ RADIO_BLOCK_NONE);
+ id = radio_client_add_owner_changed_handler(client,
+ test_client_inc_cb, &owner_changed);
+ g_assert(id);
+ g_assert_cmpint(radio_request_group_block(group1), ==,
+ RADIO_BLOCK_QUEUED);
+ g_assert_cmpint(radio_request_group_block_status(group1), ==,
+ RADIO_BLOCK_QUEUED);
+ g_assert_cmpint(owner_changed, == ,0);
+
+ group2 = radio_request_group_new(client);
+ g_assert(group2);
+ g_assert_cmpint(radio_request_group_block(group2), ==,
+ RADIO_BLOCK_QUEUED);
+ g_assert_cmpint(radio_request_group_block(group2), ==,
+ RADIO_BLOCK_QUEUED);
+ g_assert_cmpint(radio_request_group_block_status(group2), ==,
+ RADIO_BLOCK_QUEUED);
+
+ group3 = radio_request_group_new(client);
+ g_assert(group3);
+ g_assert_cmpint(radio_request_group_block(group3), ==,
+ RADIO_BLOCK_QUEUED);
+ g_assert_cmpint(radio_request_group_block_status(group3), ==,
+ RADIO_BLOCK_QUEUED);
+
+ /* Create more requests (in the opposite order) */
+ req3 = radio_request_new2(group3, RADIO_REQ_GET_MUTE, NULL,
+ test_group3_complete2_cb, test_group3_destroy_continue_cb, &test);
+ g_assert(req3);
+ g_assert(radio_request_submit(req3));
+ g_assert_cmpint(req3->state, == ,RADIO_REQUEST_STATE_QUEUED);
+
+ req2 = radio_request_new2(group2, RADIO_REQ_GET_MUTE, NULL,
+ test_group3_complete2_cb, test_group3_destroy_continue_cb, &test);
+ g_assert(req2);
+ g_assert(radio_request_submit(req2));
+ g_assert_cmpint(req2->state, == ,RADIO_REQUEST_STATE_QUEUED);
+
+ req1 = radio_request_new2(group1, RADIO_REQ_GET_MUTE, NULL,
+ test_group3_complete2_cb, test_group3_destroy_continue_cb, &test);
+ g_assert(req1);
+ g_assert(radio_request_submit(req1));
+ g_assert_cmpint(req1->state, == ,RADIO_REQUEST_STATE_QUEUED);
+
+ /* Wait for the first request to complete */
+ test_run(&test_opt, test.loop);
+
+ /* The first group becomes the owner */
+ g_assert_cmpint(owner_changed, == ,1);
+ g_assert_cmpint(radio_request_group_block_status(group1), ==,
+ RADIO_BLOCK_ACQUIRED);
+
+ /* And its request gets submitted */
+ g_assert_cmpint(req1->state, > ,RADIO_REQUEST_STATE_QUEUED);
+ g_idle_add(test_unref_request_later, req1);
+ test_run(&test_opt, test.loop);
+
+ /* Freeing the group allows the next one to become the owner */
+ g_assert_cmpint(radio_request_group_block_status(group2), ==,
+ RADIO_BLOCK_QUEUED);
+ g_assert_cmpint(owner_changed, == ,1);
+ radio_request_group_unref(group1);
+ g_assert_cmpint(owner_changed, == ,2);
+ g_assert_cmpint(radio_request_group_block_status(group2), ==,
+ RADIO_BLOCK_ACQUIRED);
+
+ /* And its request gets submitted */
+ g_assert_cmpint(req2->state, > ,RADIO_REQUEST_STATE_QUEUED);
+ g_idle_add(test_unref_request_later, req2);
+ test_run(&test_opt, test.loop);
+
+ /* Drop group2 */
+ g_assert_cmpint(radio_request_group_block_status(group3), ==,
+ RADIO_BLOCK_QUEUED);
+ g_assert_cmpint(owner_changed, == ,2);
+ radio_request_group_unblock(group2);
+ g_assert_cmpint(owner_changed, == ,3);
+ g_assert_cmpint(radio_request_group_block_status(group3), ==,
+ RADIO_BLOCK_ACQUIRED);
+ radio_request_group_unref(group2);
+
+ /* Wait for the last request to complete */
+ g_assert_cmpint(req3->state, > ,RADIO_REQUEST_STATE_QUEUED);
+ g_idle_add(test_unref_request_later, req3);
+ test_run(&test_opt, test.loop);
+
+ /* Cleanup */
+ radio_request_group_unref(group3);
+ g_main_loop_unref(test.loop);
+ test_common_cleanup(&test.common);
+}
+
+/*==========================================================================*
+ * block
+ *==========================================================================*/
+
+typedef struct test_block_data {
+ TestCommon common;
+ GMainLoop* loop;
+ int completed;
+ int destroyed;
+} TestBlock;
+
+static
+void
+test_block_complete_cb(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestBlock* test = user_data;
+
+ g_assert_cmpint(status, == ,RADIO_TX_STATUS_OK);
+ g_assert_cmpint(resp, == ,RADIO_RESP_GET_MUTE);
+ g_assert_cmpint(error, == ,RADIO_ERROR_NONE);
+ g_assert(req->blocking || test->completed > 0);
+ test->completed++;
+ GDEBUG("completion %u", test->completed);
+ g_assert_cmpint(test->destroyed, < ,test->completed);
+}
+
+static
+void
+test_block_destroy_cb(
+ gpointer user_data)
+{
+ TestBlock* test = user_data;
+
+ g_assert(test->completed > 0);
+ g_assert_cmpint(test->destroyed, < ,test->completed);
+ test->destroyed++;
+ GDEBUG("destruction %u", test->destroyed);
+ if (test->destroyed == 3) {
+ test_quit_later(test->loop);
+ }
+}
+
+static
+void
+test_block(
+ void)
+{
+ RadioClient* client;
+ RadioRequest* req;
+ TestBlock test;
+
+ memset(&test, 0, sizeof(test));
+ test_common_init(&test.common);
+ test_common_connected(&test.common);
+ test.loop = g_main_loop_new(NULL, FALSE);
+ client = test.common.client;
+
+ /* One blocking request */
+ req = radio_request_new(client, RADIO_REQ_GET_MUTE, NULL,
+ test_block_complete_cb, test_block_destroy_cb, &test);
+ g_assert(req);
+ g_assert(req->serial);
+ radio_request_set_blocking(req, TRUE);
+ g_assert(radio_request_submit(req));
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_PENDING);
+ radio_request_unref(req);
+
+ /* And two non-blocking */
+ req = radio_request_new(client, RADIO_REQ_GET_MUTE, NULL,
+ test_block_complete_cb, test_block_destroy_cb, &test);
+ g_assert(req);
+ g_assert(req->serial);
+ g_assert(radio_request_submit(req));
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_QUEUED);
+ radio_request_unref(req);
+
+ req = radio_request_new(client, RADIO_REQ_GET_MUTE, NULL,
+ test_block_complete_cb, test_block_destroy_cb, &test);
+ g_assert(req);
+ g_assert(req->serial);
+ g_assert(radio_request_submit(req));
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_QUEUED);
+ radio_request_unref(req);
+
+ test_run(&test_opt, test.loop);
+
+ g_assert_cmpint(test.completed, == ,3);
+ g_assert_cmpint(test.destroyed, == ,3);
+
+ /* Cleanup */
+ g_main_loop_unref(test.loop);
+ test_common_cleanup(&test.common);
+}
+
+/*==========================================================================*
+ * block_timeout
+ *==========================================================================*/
+
+static
+void
+test_block_timeout_complete1_cb(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ g_assert_cmpint(status, == ,RADIO_TX_STATUS_TIMEOUT);
+ g_assert_cmpint(resp, == ,RADIO_RESP_NONE);
+ g_assert_cmpint(error, == ,RADIO_ERROR_NONE);
+ g_assert(req->blocking);
+ g_assert(!test->completed);
+ test->completed++;
+ GDEBUG("block timed out");
+}
+
+static
+void
+test_block_timeout_complete2_cb(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ g_assert_cmpint(status, == ,RADIO_TX_STATUS_OK);
+ g_assert_cmpint(resp, == ,RADIO_RESP_GET_MUTE);
+ g_assert_cmpint(error, == ,RADIO_ERROR_NONE);
+ g_assert_cmpint(test->completed, == ,1);
+ test->completed++;
+ GDEBUG("second request completed");
+}
+
+static
+void
+test_block_timeout_destroy_cb(
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ test->destroyed++;
+ GDEBUG("destruction %u", test->destroyed);
+ g_assert_cmpint(test->completed, == ,test->destroyed);
+ if (test->destroyed == 2) {
+ test_quit_later(test->loop);
+ }
+}
+
+static
+void
+test_block_timeout(
+ void)
+{
+ TestSimple test;
+ RadioClient* client = test_simple_init(&test);
+ RadioRequest* req = radio_request_new(client, IGNORE_REQ, NULL,
+ test_block_timeout_complete1_cb, test_block_timeout_destroy_cb, &test);
+
+ test_common_connected(&test.common);
+
+ /* Blocking request */
+ g_assert(req);
+ g_assert(req->serial);
+ radio_request_set_blocking(req, TRUE);
+ radio_request_set_timeout(req, 100);
+ g_assert(radio_request_submit(req));
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_PENDING);
+ radio_request_unref(req);
+
+ /* And non-blocking */
+ req = radio_request_new(client, RADIO_REQ_GET_MUTE, NULL,
+ test_block_timeout_complete2_cb, test_block_timeout_destroy_cb, &test);
+ g_assert(req);
+ g_assert(req->serial);
+ g_assert(radio_request_submit(req));
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_QUEUED);
+ radio_request_unref(req);
+
+ /* And wait for both request to get destroyed */
+ test_run(&test_opt, test.loop);
+
+ g_assert_cmpint(test.completed, == ,2);
+ g_assert_cmpint(test.destroyed, == ,2);
+
+ /* Cleanup */
+ test_simple_cleanup(&test);
+}
+
+/*==========================================================================*
+ * block_retry
+ *==========================================================================*/
+
+static
+void
+test_block_retry_complete1_cb(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ g_assert_cmpint(status, == ,RADIO_TX_STATUS_OK);
+ g_assert_cmpint(resp, == ,ERROR_RESP);
+ g_assert_cmpint(error, == ,RADIO_ERROR_GENERIC_FAILURE);
+ g_assert_cmpint(req->retry_count, == ,req->max_retries);
+ g_assert(req->blocking);
+ g_assert(!test->completed);
+ test->completed++;
+ GDEBUG("block timed out");
+}
+
+static
+void
+test_block_retry_complete2_cb(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ g_assert_cmpint(status, == ,RADIO_TX_STATUS_OK);
+ g_assert_cmpint(resp, == ,RADIO_RESP_GET_MUTE);
+ g_assert_cmpint(error, == ,RADIO_ERROR_NONE);
+ g_assert_cmpint(test->completed, == ,1);
+ test->completed++;
+ GDEBUG("second request completed");
+ test_quit_later(test->loop);
+}
+
+static
+void
+test_block_retry_destroy_cb(
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ test->destroyed++;
+ GDEBUG("destruction %u", test->destroyed);
+ g_assert_cmpint(test->completed, >= ,test->destroyed);
+}
+
+static
+void
+test_block_retry(
+ void)
+{
+ TestSimple test;
+ RadioClient* client = test_simple_init(&test);
+ RadioRequest* req = radio_request_new(client, ERROR_REQ, NULL,
+ test_block_retry_complete1_cb, test_block_retry_destroy_cb, &test);
+
+ test_common_connected(&test.common);
+
+ /* Make it blocking and retriable */
+ g_assert(req);
+ g_assert(req->serial);
+ radio_request_set_blocking(req, TRUE);
+ radio_request_set_retry(req, 10, 5);
+ g_assert(radio_request_submit(req));
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_PENDING);
+ radio_request_unref(req);
+
+ /* And non-blocking */
+ req = radio_request_new(client, RADIO_REQ_GET_MUTE, NULL,
+ test_block_retry_complete2_cb, test_block_retry_destroy_cb, &test);
+ g_assert(req);
+ g_assert(req->serial);
+ g_assert(radio_request_submit(req));
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_QUEUED);
+ radio_request_unref(req);
+
+ /* And wait for both request to get destroyed */
+ test_run(&test_opt, test.loop);
+
+ g_assert_cmpint(test.completed, == ,2);
+ g_assert_cmpint(test.destroyed, == ,2);
+
+ /* Cleanup */
+ test_simple_cleanup(&test);
+}
+
+/*==========================================================================*
+ * retry
+ *==========================================================================*/
+
+#define TEST_RETRY_COUNT 2
+
+static
+void
+test_retry_complete_cb(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ GDEBUG("status %u, retry count %d", status, req->retry_count);
+ g_assert_cmpuint(req->serial, != ,req->serial2);
+ g_assert_cmpuint(req->retry_count, == ,TEST_RETRY_COUNT);
+ g_assert_cmpint(status, == ,RADIO_TX_STATUS_OK);
+ g_assert_cmpint(resp, == ,ERROR_RESP);
+ g_assert_cmpint(error, == ,RADIO_ERROR_GENERIC_FAILURE);
+ g_assert(!test->completed);
+ g_assert(!test->destroyed);
+ test->completed = TRUE;
+}
+
+static
+void
+test_retry(
+ void)
+{
+ TestSimple test;
+ RadioClient* client = test_simple_init(&test);
+ RadioRequest* req = radio_request_new(client, ERROR_REQ, NULL,
+ test_retry_complete_cb, test_simple_destroy_cb, &test);
+
+ test_common_connected(&test.common);
+
+ radio_request_set_retry_func(req, NULL); /* Use the default */
+ radio_request_set_retry(req, 10, TEST_RETRY_COUNT);
+ g_assert(radio_request_submit(req));
+ radio_request_unref(req);
+
+ test_run(&test_opt, test.loop);
+
+ g_assert(test.completed);
+ g_assert(test.destroyed);
+
+ /* Cleanup */
+ test_simple_cleanup(&test);
+}
+
+static
+void
+test_retry2(
+ void)
+{
+ int i;
+ TestSimple test;
+ RadioClient* client = test_simple_init(&test);
+ RadioRequest* req = radio_request_new(client, ERROR_REQ, NULL,
+ test_retry_complete_cb, test_simple_destroy_cb, &test);
+
+ test_common_connected(&test.common);
+
+ /* Long timeout (longer than the test timeout) */
+ radio_request_set_timeout(req, TEST_TIMEOUT_MS * 2);
+ radio_request_set_retry(req, 10, TEST_RETRY_COUNT);
+ g_assert(radio_request_submit(req));
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_PENDING);
+
+ /* Use all retries */
+ for (i = 0; i < TEST_RETRY_COUNT; i++) {
+ g_assert(radio_request_retry(req));
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_PENDING);
+ }
+
+ g_assert(!radio_request_retry(req));
+ radio_request_unref(req);
+
+ test_run(&test_opt, test.loop);
+
+ g_assert(test.completed);
+ g_assert(test.destroyed);
+
+ /* Cleanup */
+ test_simple_cleanup(&test);
+}
+
+/*==========================================================================*
+ * fail
+ *==========================================================================*/
+
+static
+void
+test_fail(
+ void)
+{
+ TestCommon test;
+ RadioRequest* req;
+ gboolean destroyed = FALSE;
+
+ test_common_init(&test);
+ test_common_connected(&test);
+
+ req = radio_request_new(test.client, RADIO_REQ_GET_MUTE, NULL,
+ test_complete_not_reached, test_destroy_once, &destroyed);
+ g_assert(req);
+ g_assert(req->serial);
+
+ /* Kill the remote object */
+ g_assert(!test.radio->dead);
+ test_gbinder_remote_object_kill(test.remote);
+ g_assert(test.radio->dead);
+
+ /* Submit stays in the NEW state since the remote object is dead */
+ g_assert(!radio_request_submit(req));
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_NEW);
+
+ g_assert(!destroyed);
+ radio_request_drop(req);
+ g_assert(destroyed);
+
+ test_common_cleanup(&test);
+}
+
+/*==========================================================================*
+ * fail_tx
+ *==========================================================================*/
+
+static
+void
+test_fail_tx(
+ void)
+{
+ TestCommon test;
+ RadioRequest* req;
+ gboolean destroyed = FALSE;
+
+ test_common_init(&test);
+ test_common_connected(&test);
+
+ req = radio_request_new(test.client, RADIO_REQ_GET_MUTE, NULL,
+ test_complete_not_reached, test_destroy_once, &destroyed);
+ g_assert(req);
+ g_assert(req->serial);
+
+ /* Fail one transaction */
+ test_gbinder_client_tx_fail_count = 1;
+
+ /* Request switches in the FAILED state */
+ g_assert(!radio_request_submit(req));
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_FAILED);
+
+ g_assert(!destroyed);
+ radio_request_drop(req);
+ g_assert(destroyed);
+
+ test_common_cleanup(&test);
+}
+
+/*==========================================================================*
+ * err
+ *==========================================================================*/
+
+static
+void
+test_err(
+ void)
+{
+ TestSimple test;
+ RadioClient* client = test_simple_init(&test);
+ RadioRequest* req = radio_request_new(client, FAIL_REQ, NULL,
+ test_simple_complete_fail_cb, test_simple_destroy_cb, &test);
+
+ g_assert(req);
+ g_assert(req->serial);
+
+ /* Just setting retry function has no effect until non-zero number of
+ * retries is set, too. */
+ radio_request_set_retry_func(req, test_retry_not_reached);
+ g_assert(radio_request_submit(req));
+ radio_request_unref(req);
+
+ test_common_connected(&test.common);
+ test_run(&test_opt, test.loop);
+
+ g_assert(test.completed);
+ g_assert(test.destroyed);
+
+ /* Cleanup */
+ test_simple_cleanup(&test);
+}
+
+static
+void
+test_err2(
+ void)
+{
+ TestSimple test;
+ RadioClient* client = test_simple_init(&test);
+ RadioRequest* req = radio_request_new(client, ERROR_REQ, NULL,
+ test_simple_complete_error_cb, test_simple_destroy_cb, &test);
+
+ g_assert(req);
+ g_assert(req->serial);
+
+ /* Will be retried once */
+ radio_request_set_retry_func(req, NULL);
+ radio_request_set_retry(req, 0, 1);
+ g_assert(radio_request_submit(req));
+ radio_request_unref(req);
+
+ test_common_connected(&test.common);
+ test_run(&test_opt, test.loop);
+
+ g_assert(test.completed);
+ g_assert(test.destroyed);
+
+ /* Cleanup */
+ test_simple_cleanup(&test);
+}
+
+/*==========================================================================*
+ * timeout
+ *==========================================================================*/
+
+static
+void
+test_timeout_complete_cb(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ GDEBUG("status %u", status);
+ g_assert_cmpint(status, == ,RADIO_TX_STATUS_TIMEOUT);
+ g_assert_cmpint(resp, == ,RADIO_RESP_NONE);
+ g_assert_cmpint(error, == ,RADIO_ERROR_NONE);
+ g_assert(!test->completed);
+ g_assert(!test->destroyed);
+ test->completed = TRUE;
+}
+
+static
+void
+test_timeout(
+ void)
+{
+ TestSimple test;
+ RadioClient* client = test_simple_init(&test);
+ RadioRequest* req = radio_request_new(client, IGNORE_REQ, NULL,
+ test_timeout_complete_cb, test_simple_destroy_cb, &test);
+
+ g_assert(req);
+ g_assert(req->serial);
+ radio_request_set_timeout(req, 2 * TEST_TIMEOUT_MS);
+ g_assert(radio_request_submit(req));
+ radio_request_set_timeout(req, 100); /* Resets the timeout */
+ radio_request_set_timeout(req, 100); /* Has no effect */
+ radio_request_unref(req);
+
+ /* And expect the request to fail */
+ test_common_connected(&test.common);
+ test_run(&test_opt, test.loop);
+
+ g_assert(test.completed);
+ g_assert(test.destroyed);
+
+ /* Cleanup */
+ test_simple_cleanup(&test);
+}
+
+/*==========================================================================*
+ * timeout2
+ *==========================================================================*/
+
+static
+void
+test_timeout2(
+ void)
+{
+ TestSimple test;
+ RadioClient* client = test_simple_init(&test);
+ /* NOTE: reusing test_timeout_complete_cb */
+ RadioRequest* req = radio_request_new(client, IGNORE_REQ, NULL,
+ test_timeout_complete_cb, test_simple_destroy_cb, &test);
+
+ g_assert(req);
+ g_assert(req->serial);
+ radio_request_set_timeout(req, 2000 * TEST_TIMEOUT_SEC);
+ g_assert(radio_request_submit(req));
+ radio_request_set_timeout(req, 100); /* Resets the timeout */
+ radio_request_set_timeout(req, 100); /* Has no effect */
+ radio_request_unref(req);
+
+ /* And expect the request to fail */
+ test_run(&test_opt, test.loop);
+
+ g_assert(test.completed);
+ g_assert(test.destroyed);
+
+ /* Cleanup */
+ test_simple_cleanup(&test);
+}
+
+/*==========================================================================*
+ * timeout3
+ *==========================================================================*/
+
+static
+void
+test_timeout3_complete_cb(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ GDEBUG("status %u", status);
+ g_assert_cmpuint(req->retry_count, == ,1);
+ g_assert_cmpint(status, == ,RADIO_TX_STATUS_TIMEOUT);
+ g_assert_cmpint(resp, == ,RADIO_RESP_NONE);
+ g_assert_cmpint(error, == ,RADIO_ERROR_NONE);
+ g_assert(!test->completed);
+ g_assert(!test->destroyed);
+ test->completed = TRUE;
+ test_quit_later(test->loop);
+}
+
+static
+void
+test_timeout3_destroy_cb(
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ GDEBUG("done");
+ g_assert(test->completed);
+ g_assert(!test->destroyed);
+ test->destroyed = TRUE;
+}
+
+static
+void
+test_timeout3(
+ void)
+{
+ TestSimple test;
+ RadioClient* client = test_simple_init(&test);
+ RadioRequest* req = radio_request_new(client, ERROR_REQ, NULL,
+ test_timeout3_complete_cb, test_timeout3_destroy_cb, &test);
+
+ g_assert(req);
+ g_assert(req->serial);
+ radio_request_set_retry(req, TEST_TIMEOUT_MS, 2);
+ radio_request_set_timeout(req, 2 * TEST_TIMEOUT_MS);
+ g_assert(radio_request_submit(req));
+ radio_request_set_timeout(req, 100); /* Resets the timeout */
+ radio_request_set_timeout(req, 100); /* Has no effect */
+
+ /* And expect the request to fail */
+ test_common_connected(&test.common);
+ test_run(&test_opt, test.loop);
+
+ g_assert(test.completed);
+ g_assert(!test.destroyed);
+ radio_request_unref(req);
+ g_assert(test.destroyed);
+
+ /* Cleanup */
+ test_simple_cleanup(&test);
+}
+
+/*==========================================================================*
+ * timeout4
+ *==========================================================================*/
+
+static
+void
+test_timeout4(
+ void)
+{
+ TestSimple test;
+ RadioRequest* req1;
+ RadioRequest* req2;
+ RadioClient* client = test_simple_init(&test);
+
+ test_common_connected(&test.common);
+
+ /* No effect, already using the default value */
+ radio_client_set_default_timeout(client, 0);
+
+ /* This request will use long timeout which won't expire */
+ req1 = radio_request_new(client, IGNORE_REQ, NULL,
+ test_complete_not_reached, NULL, NULL);
+ g_assert(req1);
+ g_assert(req1->serial);
+ radio_request_set_timeout(req1, TEST_TIMEOUT_MS * 2);
+ g_assert(radio_request_submit(req1));
+
+ /* And this one will time out quickly */
+ req2 = radio_request_new(client, IGNORE_REQ, NULL,
+ test_timeout_complete_cb, test_simple_destroy_cb, &test);
+ g_assert(req2);
+ g_assert(req2->serial);
+ g_assert(radio_request_submit(req2));
+ radio_request_unref(req2);
+ radio_client_set_default_timeout(client, 100);
+ radio_client_set_default_timeout(client, 100); /* Has no effect */
+
+ /* Wait for the secong request to time out */
+ test_run(&test_opt, test.loop);
+
+ g_assert(test.completed);
+ g_assert(test.destroyed);
+
+ /* The first one is still pending */
+ g_assert_cmpint(req1->state, == ,RADIO_REQUEST_STATE_PENDING);
+ radio_request_cancel(req1);
+ g_assert_cmpint(req1->state, == ,RADIO_REQUEST_STATE_CANCELLED);
+ g_assert(!radio_request_retry(req1));
+ radio_request_unref(req1);
+
+ /* Cleanup */
+ test_simple_cleanup(&test);
+}
+
+/*==========================================================================*
+ * destroy
+ *==========================================================================*/
+
+static
+void
+test_destroy(
+ void)
+{
+ TestSimple test;
+ RadioClient* client = test_simple_init(&test);
+ RadioRequest* req = radio_request_new(client, RADIO_REQ_GET_MUTE, NULL,
+ test_simple_complete_fail_cb, test_simple_destroy_cb, &test);
+
+ g_assert(req);
+ g_assert(req->serial);
+ g_assert(radio_request_submit(req));
+ radio_request_unref(req);
+
+ /* Destroy the client without waiting for request to complete */
+ radio_client_unref(client);
+ test.common.client = NULL;
+
+ /* And expect it to fail */
+ test_run(&test_opt, test.loop);
+
+ g_assert(test.completed);
+ g_assert(test.destroyed);
+
+ /* Cleanup */
+ test_simple_cleanup(&test);
+}
+
+/*==========================================================================*
+ * death
+ *==========================================================================*/
+
+#define TEST_DEATH_REQ_COUNT 5
+
+static
+void
+test_death_destroy_cb(
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ test->destroyed++;
+ GDEBUG("req %d done", test->destroyed);
+ g_assert_cmpint(test->completed, == ,test->destroyed);
+ if (test->destroyed == TEST_DEATH_REQ_COUNT) {
+ test_quit_later(test->loop);
+ }
+}
+
+static
+void
+test_death_complete_cb(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ test->completed++;
+ GDEBUG("req %d status %u", test->completed, status);
+ g_assert_cmpint(status, == ,RADIO_TX_STATUS_FAILED);
+ g_assert_cmpint(resp, == ,RADIO_RESP_NONE);
+ g_assert_cmpint(error, == ,RADIO_ERROR_NONE);
+}
+
+static
+void
+test_death(
+ void)
+{
+ TestSimple test;
+ RadioClient* client = test_simple_init(&test);
+ RadioRequest* req = radio_request_new(client, RADIO_REQ_GET_MUTE, NULL,
+ test_death_complete_cb, test_death_destroy_cb, &test);
+ int i, death_count = 0;
+ gulong id = radio_client_add_death_handler(client, test_client_inc_cb,
+ &death_count);
+
+ /* Make this one blocking */
+ radio_request_set_blocking(req, TRUE);
+ g_assert(req);
+ g_assert(req->serial);
+ g_assert(radio_request_submit(req));
+ radio_request_unref(req);
+
+ /* And let these sit in the queue */
+ for (i = 1; i < TEST_DEATH_REQ_COUNT; i++) {
+ req = radio_request_new(client, RADIO_REQ_GET_MUTE, NULL,
+ test_death_complete_cb, test_death_destroy_cb, &test);
+ g_assert(req);
+ g_assert(req->serial);
+ g_assert(radio_request_submit(req));
+ radio_request_unref(req);
+ }
+
+ /* Kill the remote object */
+ g_assert(!test.common.radio->dead);
+ g_assert(!radio_client_dead(client));
+ test_gbinder_remote_object_kill(test.common.remote);
+ g_assert(test.common.radio->dead);
+ g_assert(radio_client_dead(client));
+ g_assert_cmpint(death_count, == ,1);
+
+ /* And expect all requests to fail */
+ test_run(&test_opt, test.loop);
+
+ g_assert_cmpint(test.completed, == ,TEST_DEATH_REQ_COUNT);
+ g_assert_cmpint(test.destroyed, == ,TEST_DEATH_REQ_COUNT);
+ g_assert_cmpint(death_count, == ,1);
+
+ /* This one is going to fail immediatelt because the client is dead */
+ req = radio_request_new(client, RADIO_REQ_GET_MUTE, NULL,
+ test_complete_not_reached, NULL, NULL);
+ g_assert(req);
+ g_assert(req->serial);
+ g_assert(!radio_request_submit(req));
+ radio_request_drop(req);
+
+ /* Cleanup */
+ radio_client_remove_handler(client, id);
+ test_simple_cleanup(&test);
+}
+
+/*==========================================================================*
+ * Common
+ *==========================================================================*/
+
+#define TEST_PREFIX "/client/"
+#define TEST_(t) TEST_PREFIX t
+
+int main(int argc, char* argv[])
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_add_func(TEST_("null"), test_null);
+ g_test_add_func(TEST_("basic"), test_basic);
+ g_test_add_func(TEST_("cancel"), test_cancel);
+ g_test_add_func(TEST_("cancel_queue"), test_cancel_queue);
+ g_test_add_func(TEST_("ind"), test_ind);
+ g_test_add_func(TEST_("resp"), test_resp);
+ g_test_add_func(TEST_("group"), test_group);
+ g_test_add_func(TEST_("group2"), test_group2);
+ g_test_add_func(TEST_("group3"), test_group3);
+ g_test_add_func(TEST_("block"), test_block);
+ g_test_add_func(TEST_("block_timeout"), test_block_timeout);
+ g_test_add_func(TEST_("block_retry"), test_block_retry);
+ g_test_add_func(TEST_("retry"), test_retry);
+ g_test_add_func(TEST_("retry2"), test_retry2);
+ g_test_add_func(TEST_("fail"), test_fail);
+ g_test_add_func(TEST_("fail_tx"), test_fail_tx);
+ g_test_add_func(TEST_("err"), test_err);
+ g_test_add_func(TEST_("err2"), test_err2);
+ g_test_add_func(TEST_("timeout"), test_timeout);
+ g_test_add_func(TEST_("timeout2"), test_timeout2);
+ g_test_add_func(TEST_("timeout3"), test_timeout3);
+ g_test_add_func(TEST_("timeout4"), test_timeout4);
+ g_test_add_func(TEST_("death"), test_death);
+ g_test_add_func(TEST_("destroy"), test_destroy);
+ test_init(&test_opt, argc, argv);
+ return g_test_run();
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/unit_config/Makefile
^
|
@@ -0,0 +1,5 @@
+# -*- Mode: makefile-gmake -*-
+
+EXE = unit_config
+
+include ../common/Makefile
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/unit_config/unit_config.c
^
|
@@ -0,0 +1,918 @@
+/*
+ * Copyright (C) 2022 Jolla Ltd.
+ * Copyright (C) 2022 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#include "test_common.h"
+#include "test_gbinder.h"
+
+#include "radio_config.h"
+#include "radio_request_p.h"
+
+#include <gutil_strv.h>
+#include <gutil_log.h>
+
+#define DEV GBINDER_DEFAULT_HWBINDER
+
+static TestOpt test_opt;
+
+static const GBinderClientIfaceInfo radio_config_ind_iface_info[] = {
+ {RADIO_CONFIG_INDICATION_1_0, RADIO_CONFIG_1_0_IND_LAST }
+};
+
+static const GBinderClientIfaceInfo radio_config_resp_iface_info[] = {
+ {RADIO_CONFIG_RESPONSE_1_2, RADIO_CONFIG_1_2_RESP_LAST },
+ {RADIO_CONFIG_RESPONSE_1_1, RADIO_CONFIG_1_1_RESP_LAST },
+ {RADIO_CONFIG_RESPONSE_1_0, RADIO_CONFIG_1_0_RESP_LAST }
+};
+
+static const char* const radio_config_req_ifaces[] = {
+ RADIO_CONFIG_1_2,
+ RADIO_CONFIG_1_1,
+ RADIO_CONFIG_1_0,
+ NULL
+};
+
+static const char* const radio_config_fqnames[] = {
+ RADIO_CONFIG_1_0_FQNAME,
+ RADIO_CONFIG_1_1_FQNAME,
+ RADIO_CONFIG_1_2_FQNAME
+};
+
+static
+void
+test_complete_not_reached(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_CONFIG_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ g_assert_not_reached();
+}
+
+static
+void
+test_destroy_once(
+ gpointer user_data)
+{
+ gboolean* destroyed = user_data;
+
+ g_assert(!*destroyed);
+ *destroyed = TRUE;
+}
+
+static
+void
+test_ind_not_reached(
+ RadioConfig* config,
+ RADIO_CONFIG_IND code,
+ const GBinderReader* args,
+ gpointer user_data)
+{
+ g_assert_not_reached();
+}
+
+static
+void
+test_inc_cb(
+ gpointer user_data)
+{
+ (*((int*)user_data))++;
+}
+
+static
+void
+test_config_inc_cb(
+ RadioConfig* config,
+ gpointer user_data)
+{
+ (*((int*)user_data))++;
+}
+
+static
+RADIO_CONFIG_RESP
+test_config_req_resp(
+ RADIO_CONFIG_REQ req)
+{
+ switch (req) {
+#define REQ_RESP_(req,resp,Name,NAME) \
+ case RADIO_CONFIG_REQ_##NAME: return RADIO_CONFIG_RESP_##NAME;
+ RADIO_CONFIG_CALL_1_0(REQ_RESP_)
+ RADIO_CONFIG_CALL_1_1(REQ_RESP_)
+#undef REQ_RESP_
+ case RADIO_CONFIG_REQ_SET_RESPONSE_FUNCTIONS:
+ return RADIO_CONFIG_RESP_NONE;
+ case RADIO_CONFIG_REQ_ANY:
+ break;
+ }
+ g_assert_not_reached();
+ return RADIO_CONFIG_RESP_NONE;
+}
+
+/*==========================================================================*
+ * Test IRadioConfig service
+ *==========================================================================*/
+
+typedef struct test_config_service {
+ GBinderLocalObject* obj;
+ GBinderClient* resp_client;
+ GBinderClient* ind_client;
+ GHashTable* req_count;
+} TestConfigService;
+
+#define FAIL_REQ RADIO_CONFIG_REQ_GET_PHONE_CAPABILITY
+#define ERROR_REQ RADIO_CONFIG_REQ_SET_SIM_SLOTS_MAPPING
+#define ERROR_RESP RADIO_CONFIG_RESP_SET_SIM_SLOTS_MAPPING
+#define IGNORE_REQ RADIO_CONFIG_REQ_SET_MODEMS_CONFIG
+
+static
+int
+test_config_service_req_count(
+ TestConfigService* service,
+ RADIO_CONFIG_REQ req)
+{
+ return GPOINTER_TO_INT(g_hash_table_lookup(service->req_count,
+ GINT_TO_POINTER(req)));
+}
+
+static
+GBinderLocalReply*
+test_config_service_txproc(
+ GBinderLocalObject* obj,
+ GBinderRemoteRequest* req,
+ guint code,
+ guint flags,
+ int* status,
+ void* user_data)
+{
+ TestConfigService* service = user_data;
+ const char* iface = gbinder_remote_request_interface(req);
+
+ if (gutil_strv_contains((const GStrV*)radio_config_req_ifaces, iface)) {
+ const int count = test_config_service_req_count(service, code) + 1;
+ GBinderReader reader;
+
+ GDEBUG("%s %s %d", iface, radio_config_req_name(NULL, code), count);
+ g_hash_table_insert(service->req_count, GINT_TO_POINTER(code),
+ GINT_TO_POINTER(count));
+
+ gbinder_remote_request_init_reader(req, &reader);
+ if (code == RADIO_CONFIG_REQ_SET_RESPONSE_FUNCTIONS) {
+ GBinderRemoteObject* resp_obj = gbinder_reader_read_object(&reader);
+ GBinderRemoteObject* ind_obj = gbinder_reader_read_object(&reader);
+
+ g_assert(resp_obj);
+ g_assert(ind_obj);
+ gbinder_client_unref(service->resp_client);
+ gbinder_client_unref(service->ind_client);
+ service->resp_client = gbinder_client_new2(resp_obj,
+ TEST_ARRAY_AND_COUNT(radio_config_resp_iface_info));
+ service->ind_client = gbinder_client_new2(ind_obj,
+ TEST_ARRAY_AND_COUNT(radio_config_ind_iface_info));
+ gbinder_remote_object_unref(resp_obj);
+ gbinder_remote_object_unref(ind_obj);
+ } else if (code == FAIL_REQ) {
+ GDEBUG("failing request transaction");
+ *status = GBINDER_STATUS_FAILED;
+ return NULL;
+ } else if (code == IGNORE_REQ) {
+ GDEBUG("ignoring request transaction");
+ } else {
+ RadioResponseInfo info;
+ GBinderWriter writer;
+ RADIO_CONFIG_RESP resp_code = test_config_req_resp(code);
+ GBinderLocalRequest* resp = gbinder_client_new_request2
+ (service->resp_client, resp_code);
+
+ memset(&info, 0, sizeof(info));
+ info.type = RADIO_RESP_SOLICITED;
+ info.error = (code == ERROR_REQ) ?
+ RADIO_ERROR_GENERIC_FAILURE :
+ RADIO_ERROR_NONE;
+ g_assert(gbinder_reader_read_uint32(&reader, &info.serial));
+ GDEBUG("serial %08x", info.serial);
+
+ g_assert(resp);
+ gbinder_local_request_init_writer(resp, &writer);
+ gbinder_writer_append_buffer_object(&writer, &info, sizeof(info));
+
+ switch (code) {
+ case RADIO_CONFIG_REQ_SET_PREFERRED_DATA_MODEM:
+ g_assert(gbinder_client_transact(service->resp_client,
+ resp_code, GBINDER_TX_FLAG_ONEWAY, resp, NULL, NULL, NULL));
+ break;
+ default:
+ /* No expecting anything else */
+ g_assert_not_reached();
+ break;
+ }
+ gbinder_local_request_unref(resp);
+ }
+ *status = GBINDER_STATUS_OK;
+ return NULL;
+ } else {
+ GDEBUG("%s %u", iface, code);
+ *status = GBINDER_STATUS_FAILED;
+ return NULL;
+ }
+}
+
+static
+void
+test_config_service_init(
+ TestConfigService* service)
+{
+ memset(service, 0, sizeof(*service));
+ service->obj = test_gbinder_local_object_new(NULL,
+ test_config_service_txproc, service);
+ service->req_count = g_hash_table_new(g_direct_hash, g_direct_equal);
+}
+
+static
+void
+test_config_service_cleanup(
+ TestConfigService* service)
+{
+ g_hash_table_destroy(service->req_count);
+ gbinder_client_unref(service->resp_client);
+ gbinder_client_unref(service->ind_client);
+ gbinder_local_object_unref(service->obj);
+ memset(service, 0, sizeof(*service));
+}
+
+/*==========================================================================*
+ * Common setup for all tests
+ *==========================================================================*/
+
+typedef struct test_common {
+ TestConfigService service;
+ GBinderServiceManager* sm;
+ GBinderRemoteObject* remote[RADIO_CONFIG_INTERFACE_COUNT];
+ RadioConfig* client;
+} TestCommon;
+
+static
+RadioConfig*
+test_common_init(
+ TestCommon* test,
+ RADIO_CONFIG_INTERFACE version)
+{
+ RADIO_CONFIG_INTERFACE v;
+
+ memset(test, 0, sizeof(*test));
+ test->sm = gbinder_servicemanager_new(DEV);
+ test_config_service_init(&test->service);
+ for (v = RADIO_CONFIG_INTERFACE_1_0; v <= version; v++) {
+ test->remote[v] = test_gbinder_servicemanager_new_service(test->sm,
+ radio_config_fqnames[v], test->service.obj);
+ }
+ test->client = radio_config_new();
+ g_assert(test->client);
+ return test->client;
+}
+
+static
+void
+test_common_cleanup(
+ TestCommon* test)
+{
+ int i;
+
+ radio_config_unref(test->client);
+ test_config_service_cleanup(&test->service);
+ for (i = 0; i < G_N_ELEMENTS(test->remote); i++) {
+ gbinder_remote_object_unref(test->remote[i]);
+ }
+ gbinder_servicemanager_unref(test->sm);
+}
+
+/*==========================================================================*
+ * Another common setup
+ *==========================================================================*/
+
+typedef struct test_simple_data {
+ TestCommon common;
+ GMainLoop* loop;
+ int completed; /* Typically used as a boolean */
+ int destroyed; /* Typically used as a boolean */
+} TestSimple;
+
+static
+RadioConfig*
+test_simple_init(
+ TestSimple* test)
+{
+ memset(test, 0, sizeof(*test));
+ test->loop = g_main_loop_new(NULL, FALSE);
+ return test_common_init(&test->common, RADIO_CONFIG_INTERFACE_1_1);
+}
+
+static
+void
+test_simple_cleanup(
+ TestSimple* test)
+{
+ g_main_loop_unref(test->loop);
+ test_common_cleanup(&test->common);
+}
+
+static
+void
+test_simple_destroy_cb(
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ GDEBUG("done");
+ g_assert(test->completed);
+ g_assert(!test->destroyed);
+ test->destroyed = TRUE;
+ test_quit_later(test->loop);
+}
+
+/*==========================================================================*
+ * null
+ *==========================================================================*/
+
+static
+void
+test_null(
+ void)
+{
+ g_assert(!radio_config_ref(NULL));
+ g_assert(radio_config_dead(NULL));
+ g_assert_cmpint(radio_config_interface(NULL),==,RADIO_CONFIG_INTERFACE_NONE);
+ g_assert(!radio_config_rpc_header_size(NULL, RADIO_CONFIG_REQ_NONE));
+ g_assert(!radio_config_req_name(NULL, RADIO_CONFIG_REQ_NONE));
+ g_assert(!radio_config_resp_name(NULL, RADIO_CONFIG_RESP_NONE));
+ g_assert(!radio_config_ind_name(NULL, RADIO_CONFIG_IND_NONE));
+ g_assert(!radio_config_add_death_handler(NULL, NULL, NULL));
+ g_assert(!radio_config_add_request_observer(NULL,
+ RADIO_CONFIG_REQ_ANY, NULL, NULL));
+ g_assert(!radio_config_add_request_observer_with_priority(NULL,
+ RADIO_CONFIG_REQ_ANY, RADIO_OBSERVER_PRIORITY_LOWEST, NULL, NULL));
+ radio_config_unref(NULL);
+ g_assert(!radio_config_add_response_observer(NULL,
+ RADIO_CONFIG_RESP_ANY, NULL, NULL));
+ g_assert(!radio_config_add_response_observer_with_priority(NULL,
+ RADIO_CONFIG_RESP_ANY, RADIO_OBSERVER_PRIORITY_LOWEST, NULL, NULL));
+ g_assert(!radio_config_add_indication_observer(NULL,
+ RADIO_CONFIG_IND_ANY, NULL, NULL));
+ g_assert(!radio_config_add_indication_observer_with_priority(NULL,
+ RADIO_CONFIG_IND_ANY, RADIO_OBSERVER_PRIORITY_LOWEST, NULL, NULL));
+ g_assert(!radio_config_request_new(NULL, ERROR_REQ, NULL, NULL, NULL, NULL));
+
+ radio_config_unref(NULL);
+ radio_config_remove_handler(NULL, 0);
+ radio_config_remove_handlers(NULL, NULL, 0);
+}
+
+/*==========================================================================*
+ * name
+ *==========================================================================*/
+
+static
+void
+test_name(
+ void)
+{
+ TestCommon test;
+ RadioConfig* client = test_common_init(&test, RADIO_CONFIG_INTERFACE_1_1);
+
+ g_assert_cmpstr(radio_config_req_name(client,
+ RADIO_CONFIG_REQ_SET_RESPONSE_FUNCTIONS), == ,
+ "setResponseFunctions");
+ g_assert_cmpstr(radio_config_req_name(client,
+ RADIO_CONFIG_REQ_GET_SIM_SLOTS_STATUS), == ,
+ "getSimSlotsStatus");
+ g_assert_cmpstr(radio_config_req_name(client,
+ RADIO_CONFIG_REQ_GET_PHONE_CAPABILITY), == ,
+ "getPhoneCapability");
+ g_assert_cmpstr(radio_config_req_name(client,
+ (RADIO_CONFIG_REQ)123), == ,
+ "123");
+
+ g_assert_cmpstr(radio_config_resp_name(client,
+ RADIO_CONFIG_RESP_GET_SIM_SLOTS_STATUS), == ,
+ "getSimSlotsStatusResponse");
+ g_assert_cmpstr(radio_config_resp_name(client,
+ RADIO_CONFIG_RESP_GET_PHONE_CAPABILITY), == ,
+ "getPhoneCapabilityResponse");
+ g_assert_cmpstr(radio_config_resp_name(client,
+ (RADIO_CONFIG_RESP)1234), == ,
+ "1234");
+
+ g_assert_cmpstr(radio_config_ind_name(client,
+ RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED), == ,
+ "simSlotsStatusChanged");
+ g_assert_cmpstr(radio_config_ind_name(client,
+ (RADIO_CONFIG_IND)12345), == ,
+ "12345");
+
+ test_common_cleanup(&test);
+}
+
+/*==========================================================================*
+ * none
+ *==========================================================================*/
+
+static
+void
+test_none(
+ void)
+{
+ /* No service => no client */
+ g_assert(!radio_config_new());
+}
+
+/*==========================================================================*
+ * basic
+ *==========================================================================*/
+
+static
+void
+test_basic(
+ void)
+{
+ TestCommon test;
+ RADIO_CONFIG_INTERFACE version = RADIO_CONFIG_INTERFACE_1_0;
+ RadioConfig* client = test_common_init(&test, version);
+ RadioRequest* req;
+ int destroyed = 0;
+
+ g_assert(!radio_config_dead(client));
+ g_assert(radio_config_rpc_header_size(client,
+ RADIO_CONFIG_REQ_GET_SIM_SLOTS_STATUS));
+ g_assert_cmpint(radio_config_interface(client), == ,version);
+ g_assert(radio_config_ref(client) == client);
+ radio_config_unref(client);
+
+ /* Instances are reused */
+ g_assert(radio_config_new() == client);
+ radio_config_unref(client);
+ g_assert(radio_config_new_with_version(version) == client);
+ radio_config_unref(client);
+ g_assert(radio_config_new_with_version(RADIO_CONFIG_INTERFACE_COUNT) ==
+ client);
+ radio_config_unref(client);
+
+ /* Adding NULL observer is a nop */
+ g_assert(!radio_config_add_death_handler(client, NULL, NULL));
+ g_assert(!radio_config_add_request_observer(client,
+ RADIO_CONFIG_REQ_ANY, NULL, NULL));
+ g_assert(!radio_config_add_response_observer(client,
+ RADIO_CONFIG_RESP_ANY, NULL, NULL));
+ g_assert(!radio_config_add_indication_observer(client,
+ RADIO_CONFIG_IND_ANY, NULL, NULL));
+
+ /* Zero handler id is tolerated */
+ radio_config_remove_handler(client, 0);
+
+ /* Create and destroy the request */
+ req = radio_config_request_new(client, RADIO_CONFIG_REQ_GET_MODEMS_CONFIG,
+ NULL, NULL, test_inc_cb, &destroyed);
+ g_assert(req);
+ radio_request_unref(req);
+ g_assert(destroyed);
+
+ test_common_cleanup(&test);
+}
+
+/*==========================================================================*
+ * ind
+ *==========================================================================*/
+
+typedef struct test_ind_data {
+ TestCommon common;
+ GMainLoop* loop;
+ RADIO_CONFIG_IND ind;
+} TestInd;
+
+static
+void
+test_ind_cb(
+ RadioConfig* config,
+ RADIO_CONFIG_IND code,
+ const GBinderReader* args,
+ gpointer user_data)
+{
+ TestInd* test = user_data;
+
+ /* This one is invoked first */
+ GDEBUG("first indication %d", code);
+ g_assert_cmpint(code, == ,RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED);
+ g_assert_cmpint(test->ind, == ,RADIO_CONFIG_IND_NONE);
+ test->ind = code;
+}
+
+static
+void
+test_ind_cb2(
+ RadioConfig* config,
+ RADIO_CONFIG_IND code,
+ const GBinderReader* args,
+ gpointer user_data)
+{
+ TestInd* test = user_data;
+
+ /* This one is invoked second */
+ GDEBUG("second indication %d", code);
+ g_assert_cmpint(test->ind, == ,RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED);
+ g_assert_cmpint(code, == ,RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED);
+ test_quit_later(test->loop);
+}
+
+static
+void
+test_ind(
+ void)
+{
+ GBinderLocalRequest* req;
+ GBinderClient* ind_client;
+ RadioConfig* client;
+ TestInd test;
+ gulong id[2];
+
+ memset(&test, 0, sizeof(test));
+ test.loop = g_main_loop_new(NULL, FALSE);
+ client = test_common_init(&test.common, RADIO_CONFIG_INTERFACE_1_1);
+ ind_client = test.common.service.ind_client;
+
+ /* Register and unregister one listener */
+ id[0] = radio_config_add_indication_observer(client, RADIO_CONFIG_IND_ANY,
+ test_ind_not_reached, NULL);
+ radio_config_remove_handler(client, id[0]);
+
+ /* Register actual listeners */
+ id[0] = radio_config_add_indication_observer_with_priority(client,
+ RADIO_OBSERVER_PRIORITY_HIGHEST,
+ RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED,
+ test_ind_cb, &test);
+ id[1] = radio_config_add_indication_observer_with_priority(client,
+ RADIO_OBSERVER_PRIORITY_DEFAULT,
+ RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED,
+ test_ind_cb2, &test);
+
+ /* This one will be ignored because type is missing */
+ req = gbinder_client_new_request2(ind_client,
+ RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED);
+ g_assert_cmpint(gbinder_client_transact(ind_client,
+ RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED, GBINDER_TX_FLAG_ONEWAY,
+ req, NULL, NULL, NULL), != ,0);
+ gbinder_local_request_unref(req);
+
+ /* This one will be ignored because RADIO_IND_ACK_EXP is not expected */
+ req = gbinder_client_new_request2(ind_client,
+ RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED);
+ gbinder_local_request_append_int32(req, RADIO_IND_ACK_EXP);
+ g_assert_cmpint(gbinder_client_transact(ind_client,
+ RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED, GBINDER_TX_FLAG_ONEWAY,
+ req, NULL, NULL, NULL), != ,0);
+ gbinder_local_request_unref(req);
+
+ /* And this one will be handled */
+ req = gbinder_client_new_request2(ind_client,
+ RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED);
+ gbinder_local_request_append_int32(req, RADIO_IND_UNSOLICITED);
+ /*
+ * RadioIndicationType should be followed by vec<SimSlotStatus> but
+ * that's not required for the purposes of this unit test.
+ */
+ g_assert_cmpint(gbinder_client_transact(ind_client,
+ RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED, GBINDER_TX_FLAG_ONEWAY,
+ req, NULL, NULL, NULL), != ,0);
+ gbinder_local_request_unref(req);
+
+ /* And wait for test_ind_cb2 to terminate the loop */
+ test_run(&test_opt, test.loop);
+ g_assert_cmpint(test.ind, == ,RADIO_CONFIG_IND_SIM_SLOTS_STATUS_CHANGED);
+
+ /* Cleanup */
+ radio_config_remove_all_handlers(client, id);
+ g_main_loop_unref(test.loop);
+ test_common_cleanup(&test.common);
+}
+
+/*==========================================================================*
+ * resp
+ *==========================================================================*/
+
+static
+void
+test_resp_observe_req1(
+ RadioConfig* config,
+ RADIO_CONFIG_REQ code,
+ GBinderLocalRequest* args,
+ gpointer user_data)
+{
+ int* observed = user_data;
+
+ GDEBUG("high prio observed req %d", code);
+ g_assert(!*observed);
+ *observed = -((int)code);
+}
+
+static
+void
+test_resp_observe_req2(
+ RadioConfig* config,
+ RADIO_CONFIG_REQ code,
+ GBinderLocalRequest* args,
+ gpointer user_data)
+{
+ int* observed = user_data;
+
+ GDEBUG("low prio observed req %d", code);
+ g_assert_cmpint(*observed, == ,-((int)code));
+ *observed = code;
+}
+
+static
+void
+test_resp_observe_resp1(
+ RadioConfig* config,
+ RADIO_CONFIG_RESP code,
+ const RadioResponseInfo* info,
+ const GBinderReader* args,
+ gpointer user_data)
+{
+ int* observed = user_data;
+
+ GDEBUG("high prio observed resp %d", code);
+ g_assert(!*observed);
+ *observed = -((int)code);
+}
+
+static
+void
+test_resp_observe_resp2(
+ RadioConfig* config,
+ RADIO_CONFIG_RESP code,
+ const RadioResponseInfo* info,
+ const GBinderReader* args,
+ gpointer user_data)
+{
+ int* observed = user_data;
+
+ GDEBUG("low prio observed resp %d", code);
+ g_assert_cmpint(*observed, == ,-((int)code));
+ *observed = code;
+}
+
+static
+void
+test_resp_complete_cb(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_CONFIG_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ GDEBUG("resp %d", resp);
+ g_assert_cmpint(status, == ,RADIO_TX_STATUS_OK);
+ g_assert_cmpint(resp, == ,RADIO_CONFIG_RESP_SET_PREFERRED_DATA_MODEM);
+ g_assert_cmpint(error, == ,RADIO_ERROR_NONE);
+ g_assert(!test->completed);
+ g_assert(!test->destroyed);
+ test->completed = TRUE;
+}
+
+static
+void
+test_resp(
+ void)
+{
+ TestSimple test;
+ RadioConfig* client = test_simple_init(&test);
+ RadioRequest* req = radio_config_request_new(client,
+ RADIO_CONFIG_REQ_SET_PREFERRED_DATA_MODEM, NULL,
+ test_resp_complete_cb, test_simple_destroy_cb, &test);
+ int observed_req = 0, observed_resp = 0;
+ gulong id[4];
+
+ id[0] = radio_config_add_request_observer_with_priority(client,
+ RADIO_OBSERVER_PRIORITY_HIGHEST, RADIO_CONFIG_REQ_ANY,
+ test_resp_observe_req1, &observed_req);
+ id[1] = radio_config_add_request_observer_with_priority(client,
+ RADIO_OBSERVER_PRIORITY_LOWEST, RADIO_CONFIG_REQ_ANY,
+ test_resp_observe_req2, &observed_req);
+ id[2] = radio_config_add_response_observer_with_priority(client,
+ RADIO_OBSERVER_PRIORITY_HIGHEST, RADIO_CONFIG_RESP_ANY,
+ test_resp_observe_resp1, &observed_resp);
+ id[3] = radio_config_add_response_observer_with_priority(client,
+ RADIO_OBSERVER_PRIORITY_LOWEST, RADIO_CONFIG_RESP_ANY,
+ test_resp_observe_resp2, &observed_resp);
+
+ g_assert(radio_request_submit(req));
+ radio_request_unref(req);
+
+ test_run(&test_opt, test.loop);
+
+ g_assert(test.completed);
+ g_assert(test.destroyed);
+ g_assert_cmpint(observed_req,==,RADIO_CONFIG_REQ_SET_PREFERRED_DATA_MODEM);
+ g_assert_cmpint(observed_resp,==,RADIO_CONFIG_RESP_SET_PREFERRED_DATA_MODEM);
+
+ /* Cleanup */
+ radio_config_remove_all_handlers(client, id);
+ test_simple_cleanup(&test);
+}
+
+/*==========================================================================*
+ * cancel
+ *==========================================================================*/
+
+static
+void
+test_cancel(
+ void)
+{
+ TestCommon test;
+ gboolean destroyed = FALSE;
+ RadioConfig* client = test_common_init(&test, RADIO_CONFIG_INTERFACE_1_0);
+ RadioRequest* req = radio_config_request_new(client,
+ RADIO_CONFIG_REQ_GET_MODEMS_CONFIG, NULL,
+ test_complete_not_reached, test_destroy_once, &destroyed);
+
+ g_assert(radio_request_submit(req));
+ radio_request_cancel(req);
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_CANCELLED);
+ radio_request_unref(req);
+
+ g_assert(destroyed);
+ test_common_cleanup(&test);
+}
+
+/*==========================================================================*
+ * fail_tx
+ *==========================================================================*/
+
+static
+void
+test_fail_tx(
+ void)
+{
+ TestCommon test;
+ gboolean destroyed = FALSE;
+ RadioConfig* client = test_common_init(&test, RADIO_CONFIG_INTERFACE_1_0);
+ RadioRequest* req = radio_config_request_new(client,
+ RADIO_CONFIG_REQ_GET_MODEMS_CONFIG, NULL,
+ test_complete_not_reached, test_destroy_once, &destroyed);
+
+ g_assert(req);
+ g_assert(req->serial);
+
+ /* Fail one transaction */
+ test_gbinder_client_tx_fail_count = 1;
+
+ /* Request switches in the FAILED state */
+ g_assert(req);
+ g_assert(!radio_request_submit(req));
+ g_assert_cmpint(req->state, == ,RADIO_REQUEST_STATE_FAILED);
+
+ g_assert(!destroyed);
+ radio_request_drop(req);
+ g_assert(destroyed);
+
+ test_common_cleanup(&test);
+}
+
+/*==========================================================================*
+ * death
+ *==========================================================================*/
+
+static
+void
+test_death_complete_cb(
+ RadioRequest* req,
+ RADIO_TX_STATUS status,
+ RADIO_CONFIG_RESP resp,
+ RADIO_ERROR error,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ GDEBUG("status %u", status);
+ g_assert_cmpint(status, == ,RADIO_TX_STATUS_FAILED);
+ g_assert_cmpint(resp, == ,RADIO_CONFIG_RESP_NONE);
+ g_assert_cmpint(error, == ,RADIO_ERROR_NONE);
+ test->completed++;
+}
+
+static
+void
+test_death_destroy_cb(
+ gpointer user_data)
+{
+ TestSimple* test = user_data;
+
+ test->destroyed++;
+ GDEBUG("done");
+ g_assert_cmpint(test->completed, == ,test->destroyed);
+ test_quit_later(test->loop);
+}
+
+static
+void
+test_death(
+ void)
+{
+ TestSimple test;
+ RadioConfig* client = test_simple_init(&test);
+ RadioRequest* req = radio_config_request_new(client,
+ RADIO_CONFIG_REQ_GET_MODEMS_CONFIG, NULL,
+ test_death_complete_cb, test_death_destroy_cb, &test);
+ RADIO_CONFIG_INTERFACE v;
+ int death_count = 0;
+ gulong id = radio_config_add_death_handler(client, test_config_inc_cb,
+ &death_count);
+
+ g_assert(radio_request_submit(req));
+ radio_request_unref(req);
+
+ /* Kill the remote objects */
+ g_assert(!radio_config_dead(client));
+ for (v = RADIO_CONFIG_INTERFACE_1_0;
+ v <= radio_config_interface(client); v++) {
+ test_gbinder_remote_object_kill(test.common.remote[v]);
+ }
+ g_assert(radio_config_dead(client));
+ g_assert_cmpint(death_count, == ,1);
+
+ /* Now expect the request to fail */
+ test_run(&test_opt, test.loop);
+ g_assert(test.completed);
+ g_assert(test.destroyed);
+
+ /* Cleanup */
+ radio_config_remove_handler(client, id);
+ test_simple_cleanup(&test);
+}
+
+/*==========================================================================*
+ * Common
+ *==========================================================================*/
+
+#define TEST_PREFIX "/config/"
+#define TEST_(t) TEST_PREFIX t
+
+int main(int argc, char* argv[])
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_add_func(TEST_("null"), test_null);
+ g_test_add_func(TEST_("name"), test_name);
+ g_test_add_func(TEST_("none"), test_none);
+ g_test_add_func(TEST_("basic"), test_basic);
+ g_test_add_func(TEST_("ind"), test_ind);
+ g_test_add_func(TEST_("resp"), test_resp);
+ g_test_add_func(TEST_("cancel"), test_cancel);
+ g_test_add_func(TEST_("fail_tx"), test_fail_tx);
+ g_test_add_func(TEST_("death"), test_death);
+ test_init(&test_opt, argc, argv);
+ return g_test_run();
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/unit_instance/Makefile
^
|
@@ -0,0 +1,5 @@
+# -*- Mode: makefile-gmake -*-
+
+EXE = unit_instance
+
+include ../common/Makefile
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/unit_instance/unit_instance.c
^
|
@@ -0,0 +1,1207 @@
+/*
+ * Copyright (C) 2021-2022 Jolla Ltd.
+ * Copyright (C) 2021-2022 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#include "test_common.h"
+#include "test_gbinder.h"
+
+#include "radio_instance_p.h"
+#include "radio_util.h"
+
+#include <gutil_strv.h>
+#include <gutil_log.h>
+
+#define DEFAULT_INTERFACE RADIO_INTERFACE_1_0
+#define DEV GBINDER_DEFAULT_BINDER
+
+#define UNKNOWN_VALUE (0x7fffffff)
+#define UNKNOWN_VALUE_STR "2147483647" /* 0x7fffffff */
+#define UNKNOWN_REQ ((RADIO_REQ)UNKNOWN_VALUE)
+#define UNKNOWN_REQ_STR UNKNOWN_VALUE_STR
+#define UNKNOWN_IND ((RADIO_IND)UNKNOWN_VALUE)
+#define UNKNOWN_IND_STR UNKNOWN_VALUE_STR
+#define UNKNOWN_RESP ((RADIO_RESP)UNKNOWN_VALUE)
+#define UNKNOWN_RESP_STR UNKNOWN_VALUE_STR
+#define INVALID_IND_TYPE ((RADIO_IND_TYPE)UNKNOWN_VALUE)
+
+RadioInstance*
+radio_instance_get_with_interface(
+ const char* dev,
+ const char* name,
+ RADIO_INTERFACE version); /* Deprecated and removed from the .h file */
+
+gboolean
+radio_instance_is_dead(
+ RadioInstance* self); /* No sure why this one is missing */
+
+typedef struct test_radio_service {
+ GBinderLocalObject* obj;
+ GBinderRemoteObject* resp_obj;
+ GBinderRemoteObject* ind_obj;
+ GHashTable* req_count;
+} TestRadioService;
+
+static TestOpt test_opt;
+
+static const GBinderClientIfaceInfo radio_ind_iface_info[] = {
+ {RADIO_INDICATION_1_4, RADIO_1_4_IND_LAST },
+ {RADIO_INDICATION_1_3, RADIO_1_3_IND_LAST },
+ {RADIO_INDICATION_1_2, RADIO_1_2_IND_LAST },
+ {RADIO_INDICATION_1_1, RADIO_1_1_IND_LAST },
+ {RADIO_INDICATION_1_0, RADIO_1_0_IND_LAST }
+};
+
+static const GBinderClientIfaceInfo radio_resp_iface_info[] = {
+ {RADIO_RESPONSE_1_4, RADIO_1_4_RESP_LAST },
+ {RADIO_RESPONSE_1_3, RADIO_1_3_RESP_LAST },
+ {RADIO_RESPONSE_1_2, RADIO_1_2_RESP_LAST },
+ {RADIO_RESPONSE_1_1, RADIO_1_1_RESP_LAST },
+ {RADIO_RESPONSE_1_0, RADIO_1_0_RESP_LAST }
+};
+
+static const char* const radio_req_ifaces[] = {
+ RADIO_1_4,
+ RADIO_1_3,
+ RADIO_1_2,
+ RADIO_1_1,
+ RADIO_1_0,
+ NULL
+};
+
+static
+gboolean
+test_response_not_handled(
+ RadioInstance* radio,
+ RADIO_RESP code,
+ const RadioResponseInfo* info,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ g_assert_not_reached();
+ return FALSE;
+}
+
+static
+void
+test_response_not_observed(
+ RadioInstance* radio,
+ RADIO_RESP code,
+ const RadioResponseInfo* info,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ g_assert_not_reached();
+}
+
+/*==========================================================================*
+ * Test IRadio service
+ *==========================================================================*/
+
+static
+int
+test_service_req_count(
+ TestRadioService* service,
+ RADIO_REQ req)
+{
+ return GPOINTER_TO_INT(g_hash_table_lookup(service->req_count,
+ GINT_TO_POINTER(req)));
+}
+
+static
+GBinderLocalReply*
+test_service_txproc(
+ GBinderLocalObject* obj,
+ GBinderRemoteRequest* req,
+ guint code,
+ guint flags,
+ int* status,
+ void* user_data)
+{
+ TestRadioService* service = user_data;
+ const char* iface = gbinder_remote_request_interface(req);
+
+ if (gutil_strv_contains((const GStrV*)radio_req_ifaces, iface)) {
+ const int count = test_service_req_count(service, code) + 1;
+ GBinderReader reader;
+
+ GDEBUG("%s %s %d", iface, radio_req_name(code), count);
+ g_hash_table_insert(service->req_count, GINT_TO_POINTER(code),
+ GINT_TO_POINTER(count));
+
+ gbinder_remote_request_init_reader(req, &reader);
+ switch (code) {
+ case RADIO_REQ_SET_RESPONSE_FUNCTIONS:
+ gbinder_remote_object_unref(service->resp_obj);
+ gbinder_remote_object_unref(service->ind_obj);
+ service->resp_obj = gbinder_reader_read_object(&reader);
+ service->ind_obj = gbinder_reader_read_object(&reader);
+ g_assert(service->resp_obj);
+ g_assert(service->ind_obj);
+ break;
+ }
+ *status = GBINDER_STATUS_OK;
+ return NULL;
+ } else {
+ GDEBUG("%s %u", iface, code);
+ *status = GBINDER_STATUS_FAILED;
+ return NULL;
+ }
+}
+
+static
+void
+test_service_init(
+ TestRadioService* service)
+{
+ memset(service, 0, sizeof(*service));
+ service->obj = test_gbinder_local_object_new(NULL,
+ test_service_txproc, service);
+ service->req_count = g_hash_table_new(g_direct_hash, g_direct_equal);
+}
+
+static
+void
+test_service_cleanup(
+ TestRadioService* service)
+{
+ g_hash_table_destroy(service->req_count);
+ gbinder_remote_object_unref(service->resp_obj);
+ gbinder_remote_object_unref(service->ind_obj);
+ gbinder_local_object_unref(service->obj);
+ memset(service, 0, sizeof(*service));
+}
+
+/*==========================================================================*
+ * null
+ *==========================================================================*/
+
+static
+void
+test_null(
+ void)
+{
+ radio_instance_set_enabled(NULL, FALSE);
+ radio_instance_remove_handler(NULL, 0);
+ radio_instance_remove_handlers(NULL, NULL, 0);
+ radio_instance_unref(NULL);
+ radio_instance_cancel_request(NULL, 0);
+
+ g_assert(radio_instance_is_dead(NULL));
+ g_assert(!radio_instance_get(NULL, NULL));
+ g_assert(!radio_instance_get("", NULL));
+ g_assert(!radio_instance_get("/dev/binder", NULL));
+ g_assert(!radio_instance_get("/dev/binder", ""));
+ g_assert(!radio_instance_get_with_interface("", "", DEFAULT_INTERFACE));
+ g_assert(!radio_instance_get_with_version("foo", "bar", DEFAULT_INTERFACE));
+ g_assert(!radio_instance_new(NULL, NULL));
+ g_assert(!radio_instance_new_with_modem_and_slot(NULL, NULL, NULL, 0));
+ g_assert(!radio_instance_new_with_version(NULL, NULL, DEFAULT_INTERFACE));
+ g_assert(!radio_instance_new_with_version(NULL, "", DEFAULT_INTERFACE));
+ g_assert(!radio_instance_new_with_version(NULL, "foo", DEFAULT_INTERFACE));
+ g_assert(!radio_instance_new_request(NULL, 0));
+ g_assert(!radio_instance_ack(NULL));
+ g_assert(!radio_instance_ref(NULL));
+ g_assert(!radio_instance_rpc_header_size(NULL, 0));
+ g_assert(!radio_instance_send_request_sync(NULL, 0, NULL));
+ g_assert(!radio_instance_add_request_observer(NULL, 0, NULL, NULL));
+ g_assert(!radio_instance_add_indication_handler(NULL, 0, NULL, NULL));
+ g_assert(!radio_instance_add_indication_observer(NULL, 0, NULL, NULL));
+ g_assert(!radio_instance_add_response_handler(NULL, 0, NULL, NULL));
+ g_assert(!radio_instance_add_response_observer(NULL, 0, NULL, NULL));
+ g_assert(!radio_instance_add_ack_handler(NULL, NULL, NULL));
+ g_assert(!radio_instance_add_death_handler(NULL, NULL, NULL));
+ g_assert(!radio_instance_add_enabled_handler(NULL, NULL, NULL));
+ g_assert(!radio_instance_add_connected_handler(NULL, NULL, NULL));
+ g_assert(!radio_instance_req_name(NULL, UNKNOWN_REQ));
+ g_assert(!radio_instance_resp_name(NULL, UNKNOWN_RESP));
+ g_assert(!radio_instance_ind_name(NULL, UNKNOWN_IND));
+ g_assert(!radio_instance_send_request(NULL,0,NULL,NULL,NULL,NULL,NULL));
+}
+
+/*==========================================================================*
+ * basic
+ *==========================================================================*/
+
+static
+void
+test_basic(
+ void)
+{
+ GBinderServiceManager* sm = gbinder_servicemanager_new(DEV);
+ GBinderRemoteObject* remote;
+ RadioInstance* radio;
+ RadioInstance* const* radios;
+ TestRadioService service;
+ const RADIO_INTERFACE version = RADIO_INTERFACE_1_4;
+ const char* slot = "slot1";
+ const char* fqname = RADIO_1_0 "/slot1";
+ GQuark q;
+
+ /* This fails because there's no radio service */
+ g_assert(!radio_instance_new_with_version(DEV, slot, DEFAULT_INTERFACE));
+ g_assert(!radio_instance_get_all());
+
+ /* Register the service to create an instance */
+ test_service_init(&service);
+ remote = test_gbinder_servicemanager_new_service(sm, fqname, service.obj);
+ radio = radio_instance_new_with_version(DEV, slot, version);
+ g_assert(radio);
+ g_assert(service.ind_obj);
+ g_assert(service.resp_obj);
+
+ /* The second call returns new reference to the same instance */
+ g_assert(radio == radio_instance_new_with_version(DEV, slot, version));
+ radio_instance_unref(radio);
+
+ /* Test quarks */
+ q = radio_instance_ind_quark(radio, UNKNOWN_IND);
+ g_assert(q);
+ g_assert(q == radio_instance_ind_quark(radio, UNKNOWN_IND));
+
+ /* Expecting non-zero RPC header size for a valid request code */
+ g_assert(radio_instance_rpc_header_size(radio, RADIO_REQ_DIAL));
+ g_assert_cmpuint(radio_instance_rpc_header_size(radio, UNKNOWN_REQ),==,0);
+
+ /* The one we have created must still be there */
+ g_assert(radio == radio_instance_get_with_version(DEV, slot, version));
+
+ /* NULL callbacks are ignored */
+ g_assert(!radio_instance_add_request_observer(radio, 0, NULL, NULL));
+ g_assert(!radio_instance_add_indication_handler(radio, 0, NULL, NULL));
+ g_assert(!radio_instance_add_indication_observer(radio, 0, NULL, NULL));
+ g_assert(!radio_instance_add_response_handler(radio, 0, NULL, NULL));
+ g_assert(!radio_instance_add_response_observer(radio, 0, NULL, NULL));
+ g_assert(!radio_instance_add_ack_handler(radio, NULL, NULL));
+ g_assert(!radio_instance_add_death_handler(radio, NULL, NULL));
+ g_assert(!radio_instance_add_enabled_handler(radio, NULL, NULL));
+ g_assert(!radio_instance_add_connected_handler(radio, NULL, NULL));
+
+ /* Formatting unknown codes (RadioInstance owns the string) */
+ g_assert_cmpstr(radio_instance_req_name(radio, UNKNOWN_REQ), == ,
+ UNKNOWN_REQ_STR);
+ g_assert_cmpstr(radio_instance_resp_name(radio, UNKNOWN_RESP), == ,
+ UNKNOWN_RESP_STR);
+ g_assert_cmpstr(radio_instance_ind_name(radio, UNKNOWN_IND), == ,
+ UNKNOWN_IND_STR);
+ g_assert_cmpstr(radio_instance_req_name(radio,
+ RADIO_REQ_DIAL), == ,"dial");
+ g_assert_cmpstr(radio_instance_resp_name(radio,
+ RADIO_RESP_DIAL), == ,"dialResponse");
+ g_assert_cmpstr(radio_instance_ind_name(radio,
+ RADIO_IND_MODEM_RESET), == ,"modemReset");
+
+ /* The entire list consists of that one instance */
+ radios = radio_instance_get_all();
+ g_assert(radios);
+ g_assert(radios[0] == radio);
+ g_assert(!radios[1]);
+
+ radio_instance_unref(radio);
+ test_service_cleanup(&service);
+ gbinder_remote_object_unref(remote);
+ gbinder_servicemanager_unref(sm);
+}
+
+/*==========================================================================*
+ * connected
+ *==========================================================================*/
+
+typedef struct test_connected_data {
+ int observed;
+ int connected;
+} TestConnected;
+
+static
+void
+test_connected_observer_high(
+ RadioInstance* radio,
+ RADIO_IND code,
+ RADIO_IND_TYPE type,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestConnected* test = user_data;
+
+ g_assert_cmpint(test->observed % 3, == ,0);
+ g_assert(!test->observed || test->connected);
+ test->observed++;
+ GDEBUG_("%d", test->observed);
+}
+
+static
+void
+test_connected_observer_default(
+ RadioInstance* radio,
+ RADIO_IND code,
+ RADIO_IND_TYPE type,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestConnected* test = user_data;
+
+ g_assert_cmpint(test->observed % 3, == ,1);
+ g_assert_cmpint(test->connected, == ,1);
+ test->observed++;
+ GDEBUG_("%d", test->observed);
+}
+
+static
+void
+test_connected_observer_low(
+ RadioInstance* radio,
+ RADIO_IND code,
+ RADIO_IND_TYPE type,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ TestConnected* test = user_data;
+
+ g_assert_cmpint(test->observed % 3, == ,2);
+ g_assert_cmpint(test->connected, == ,1);
+ test->observed++;
+ GDEBUG_("%d", test->observed);
+}
+
+static
+void
+test_connected_cb(
+ RadioInstance* radio,
+ gpointer user_data)
+{
+ TestConnected* test = user_data;
+
+ g_assert(!test->connected);
+ test->connected++;
+ GDEBUG_("");
+}
+
+static
+void
+test_connected(
+ void)
+{
+ GBinderServiceManager* sm = gbinder_servicemanager_new(DEV);
+ GBinderRemoteObject* remote;
+ RadioInstance* radio;
+ TestRadioService service;
+ GBinderClient* ind;
+ GBinderLocalRequest* req;
+ const RADIO_INTERFACE version = RADIO_INTERFACE_1_4;
+ const char* slot = "slot1";
+ const char* fqname = RADIO_1_0 "/slot1";
+ TestConnected test;
+ gulong id[4];
+
+ memset(&test, 0, sizeof(test));
+
+ /* Register the service to create an instance */
+ test_service_init(&service);
+ remote = test_gbinder_servicemanager_new_service(sm, fqname, service.obj);
+ radio = radio_instance_new_with_version(DEV, slot, version);
+ g_assert(radio);
+ g_assert(!radio->connected);
+
+ id[0] = radio_instance_add_indication_observer_with_priority(radio,
+ RADIO_INSTANCE_PRIORITY_LOWEST, RADIO_IND_ANY,
+ test_connected_observer_low, &test);
+ id[1] = radio_instance_add_indication_observer(radio,RADIO_IND_ANY,
+ test_connected_observer_default, &test);
+ id[2] = radio_instance_add_indication_observer_with_priority(radio,
+ RADIO_INSTANCE_PRIORITY_HIGHEST + 1 /* becomes HIGHEST */,
+ RADIO_IND_ANY, test_connected_observer_high, &test);
+ id[3] = radio_instance_add_connected_handler(radio, test_connected_cb,
+ &test);
+
+ /* Issue rilConnected */
+ g_assert(service.ind_obj);
+ ind = gbinder_client_new2(service.ind_obj,
+ TEST_ARRAY_AND_COUNT(radio_ind_iface_info));
+ g_assert(ind);
+ req = gbinder_client_new_request2(ind, RADIO_IND_RIL_CONNECTED);
+ gbinder_local_request_append_int32(req, RADIO_IND_ACK_EXP);
+
+ g_assert_cmpint(gbinder_client_transact_sync_oneway(ind,
+ RADIO_IND_RIL_CONNECTED, req), == ,GBINDER_STATUS_OK);
+ g_assert_cmpint(test.observed, == ,3);
+ g_assert_cmpint(test.connected, == ,1);
+ g_assert(radio->connected);
+
+ /* Second time around observer is still called but connect handler isn't */
+ g_assert_cmpint(gbinder_client_transact_sync_oneway(ind,
+ RADIO_IND_RIL_CONNECTED, req), == ,GBINDER_STATUS_OK);
+ g_assert_cmpint(test.observed, == ,6);
+ g_assert_cmpint(test.connected, == ,1);
+ g_assert(radio->connected);
+
+ gbinder_local_request_unref(req);
+ gbinder_client_unref(ind);
+
+ radio_instance_remove_all_handlers(radio, id);
+ radio_instance_unref(radio);
+ test_service_cleanup(&service);
+ gbinder_remote_object_unref(remote);
+ gbinder_servicemanager_unref(sm);
+}
+
+/*==========================================================================*
+ * ind
+ *==========================================================================*/
+
+static
+gboolean
+test_ind_handle(
+ RadioInstance* radio,
+ RADIO_IND code,
+ RADIO_IND_TYPE type,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ int* expected = user_data;
+
+ g_assert_cmpint(code, == ,*expected);
+ *expected = RADIO_IND_NONE;
+ radio_instance_ack(radio);
+ return TRUE;
+}
+
+static
+void
+test_ind_observe(
+ RadioInstance* radio,
+ RADIO_IND code,
+ RADIO_IND_TYPE type,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ int* expected = user_data;
+
+ g_assert_cmpint(code, == ,*expected);
+ *expected = RADIO_IND_NONE;
+}
+
+static
+void
+test_ind(
+ void)
+{
+ GBinderServiceManager* sm = gbinder_servicemanager_new(DEV);
+ GBinderRemoteObject* remote;
+ RadioInstance* radio;
+ TestRadioService service;
+ GBinderClient* ind;
+ GBinderLocalRequest* req;
+ const RADIO_INTERFACE version = RADIO_INTERFACE_1_4;
+ const char* slot = "slot1";
+ const char* fqname = RADIO_1_0 "/slot1";
+ int code[2];
+ gulong id[2];
+
+ /* Register the service to create an instance */
+ test_service_init(&service);
+ remote = test_gbinder_servicemanager_new_service(sm, fqname, service.obj);
+ radio = radio_instance_new_with_version(DEV, slot, version);
+ g_assert(radio);
+
+ /* Issue invalid indication (no type) */
+ code[0] = code[1] = RADIO_IND_RIL_CONNECTED;
+ id[0] = radio_instance_add_indication_handler(radio, RADIO_IND_RIL_CONNECTED,
+ test_ind_handle, code + 0);
+ id[1] = radio_instance_add_indication_observer(radio, RADIO_IND_ANY,
+ test_ind_observe, code + 1);
+ g_assert(service.ind_obj);
+ ind = gbinder_client_new2(service.ind_obj,
+ TEST_ARRAY_AND_COUNT(radio_ind_iface_info));
+ req = gbinder_client_new_request2(ind, RADIO_IND_RIL_CONNECTED);
+ g_assert_cmpint(gbinder_client_transact_sync_oneway(ind,
+ RADIO_IND_RIL_CONNECTED, req), == ,GBINDER_STATUS_FAILED);
+
+ /* No signals issued and no acks sent */
+ g_assert_cmpint(code[0], == ,RADIO_IND_RIL_CONNECTED);
+ g_assert_cmpint(code[1], == ,RADIO_IND_RIL_CONNECTED);
+ g_assert_cmpint(test_service_req_count(&service,
+ RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,0);
+
+ /* Another invalid indication (invalid type) */
+ gbinder_local_request_append_int32(req, INVALID_IND_TYPE);
+ g_assert_cmpint(gbinder_client_transact_sync_oneway(ind,
+ RADIO_IND_RIL_CONNECTED, req), == ,GBINDER_STATUS_FAILED);
+
+ /* No signals issued and no acks sent */
+ g_assert_cmpint(code[0], == ,RADIO_IND_RIL_CONNECTED);
+ g_assert_cmpint(code[1], == ,RADIO_IND_RIL_CONNECTED);
+ g_assert_cmpint(test_service_req_count(&service,
+ RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,0);
+
+ /* Build a valid request and try again */
+ gbinder_local_request_unref(req);
+ req = gbinder_client_new_request2(ind, RADIO_IND_RIL_CONNECTED);
+ gbinder_local_request_append_int32(req, RADIO_IND_ACK_EXP);
+ g_assert_cmpint(gbinder_client_transact_sync_oneway(ind,
+ RADIO_IND_RIL_CONNECTED, req), == ,GBINDER_STATUS_OK);
+
+ /* This time both handler and observer are notified, ack is sent */
+ g_assert_cmpint(code[0], == ,RADIO_IND_NONE);
+ g_assert_cmpint(code[1], == ,RADIO_IND_NONE);
+ g_assert_cmpint(test_service_req_count(&service,
+ RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,1);
+
+ /* Now issue callStateChanged but only observe it (don't handle) */
+ radio_instance_remove_handlers(radio, id, 1);
+ code[1] = RADIO_IND_CALL_STATE_CHANGED;
+ g_assert_cmpint(gbinder_client_transact_sync_oneway(ind,
+ RADIO_IND_CALL_STATE_CHANGED, req), == ,GBINDER_STATUS_OK);
+ g_assert_cmpint(code[1], == ,RADIO_IND_NONE);
+ g_assert_cmpint(test_service_req_count(&service,
+ RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,2); /* Unhandled but acked */
+
+ /* Same thing but without ack */
+ gbinder_local_request_unref(req);
+ req = gbinder_client_new_request2(ind, RADIO_IND_CALL_STATE_CHANGED);
+ gbinder_local_request_append_int32(req, RADIO_IND_UNSOLICITED);
+ code[1] = RADIO_IND_CALL_STATE_CHANGED;
+ g_assert_cmpint(gbinder_client_transact_sync_oneway(ind,
+ RADIO_IND_CALL_STATE_CHANGED, req), == ,GBINDER_STATUS_OK);
+ g_assert_cmpint(code[1], == ,RADIO_IND_NONE);
+ g_assert_cmpint(test_service_req_count(&service,
+ RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,2); /* Still 2 (not acked) */
+
+ /* Unsupported interface */
+ gbinder_local_request_unref(req);
+ req = test_gbinder_local_request_new("foo");
+ g_assert_cmpint(gbinder_client_transact_sync_oneway(ind,
+ UNKNOWN_IND, req), == ,GBINDER_STATUS_FAILED);
+ gbinder_local_request_unref(req);
+ gbinder_client_unref(ind);
+
+ radio_instance_remove_all_handlers(radio, id);
+ radio_instance_unref(radio);
+ test_service_cleanup(&service);
+ gbinder_remote_object_unref(remote);
+ gbinder_servicemanager_unref(sm);
+}
+
+/*==========================================================================*
+ * req
+ *==========================================================================*/
+
+#define TEST_REQ RADIO_REQ_DIAL
+
+static
+void
+test_req_observe(
+ RadioInstance* radio,
+ RADIO_REQ code,
+ GBinderLocalRequest* args,
+ gpointer user_data)
+{
+ int* count = user_data;
+
+ (*count)++;
+ GDEBUG_("%d", *count);
+}
+
+static
+void
+test_req(
+ void)
+{
+ const char* slot = "slot1";
+ const char* fqname = RADIO_1_0 "/slot1";
+ TestRadioService service;
+ GBinderServiceManager* sm = gbinder_servicemanager_new(DEV);
+ GBinderRemoteObject* remote;
+ GBinderLocalRequest* req;
+ RadioInstance* radio;
+ int count[3];
+ gulong id[3];
+
+ test_service_init(&service);
+ remote = test_gbinder_servicemanager_new_service(sm, fqname, service.obj);
+ radio = radio_instance_new_with_version(DEV, slot, RADIO_INTERFACE_1_4);
+
+ memset(count, 0, sizeof(count));
+ id[0] = radio_instance_add_request_observer(radio, RADIO_REQ_ANY,
+ test_req_observe, count + 0);
+ id[1] = radio_instance_add_request_observer(radio, TEST_REQ,
+ test_req_observe, count + 1);
+ id[2] = radio_instance_add_request_observer(radio, TEST_REQ + 1,
+ test_req_observe, count + 2); /* Won't be called */
+ g_assert(id[0]);
+ g_assert(id[1]);
+ g_assert(id[2]);
+
+ req = radio_instance_new_request(radio, TEST_REQ);
+ gbinder_local_request_append_int32(req, 123);
+ g_assert(radio_instance_send_request_sync(radio, TEST_REQ, req));
+ g_assert_cmpint(test_service_req_count(&service, TEST_REQ), == ,1);
+ g_assert_cmpint(count[0], == ,1);
+ g_assert_cmpint(count[1], == ,1);
+ g_assert_cmpint(count[2], == ,0);
+ radio_instance_remove_all_handlers(radio, id);
+
+ radio_instance_unref(radio);
+ test_service_cleanup(&service);
+ gbinder_local_request_unref(req);
+ gbinder_remote_object_unref(remote);
+ gbinder_servicemanager_unref(sm);
+}
+
+/*==========================================================================*
+ * resp
+ *==========================================================================*/
+
+#define TEST_RESP RADIO_RESP_DIAL
+
+static
+void
+test_resp_ack_observe(
+ RadioInstance* radio,
+ RADIO_REQ code,
+ GBinderLocalRequest* args,
+ gpointer user_data)
+{
+ int* count = user_data;
+
+ (*count)++;
+ GDEBUG_("%d", *count);
+ g_assert_cmpint(code, == ,RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT);
+}
+
+static
+void
+test_resp_observe1(
+ RadioInstance* radio,
+ RADIO_RESP code,
+ const RadioResponseInfo* info,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ guint* expected = user_data;
+
+ GDEBUG("Observing resp %u (high prio)", code);
+ g_assert_cmpuint(info->serial, == ,*expected);
+ *expected = 0;
+}
+
+static
+void
+test_resp_observe2(
+ RadioInstance* radio,
+ RADIO_RESP code,
+ const RadioResponseInfo* info,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ guint* expected = user_data;
+
+ /* Serial must be already cleared by test_resp_observe1 */
+ GDEBUG("Observing resp %u (default prio)", code);
+ g_assert_cmpuint(*expected, == ,0);
+}
+
+static
+gboolean
+test_resp_handle(
+ RadioInstance* radio,
+ RADIO_RESP code,
+ const RadioResponseInfo* info,
+ const GBinderReader* reader,
+ gpointer user_data)
+{
+ guint* expected = user_data;
+
+ GDEBUG("Handling resp %u", code);
+ g_assert_cmpuint(info->serial, == ,*expected);
+ *expected = 0;
+ if (info->type == RADIO_RESP_SOLICITED_ACK_EXP) {
+ radio_instance_ack(radio);
+ }
+ return TRUE;
+}
+
+static
+void
+test_resp(
+ void)
+{
+ const char* slot = "slot2";
+ const char* fqname = RADIO_1_0 "/slot2";
+ TestRadioService service;
+ GBinderServiceManager* sm = gbinder_servicemanager_new(DEV);
+ GBinderRemoteObject* remote;
+ GBinderLocalRequest* req;
+ GBinderClient* resp;
+ RadioInstance* radio;
+ RadioResponseInfo info;
+ GBinderWriter writer;
+ guint handle_serial, observe_serial;
+ int ack_count = 0;
+ gulong id[4];
+
+ test_service_init(&service);
+
+ memset(&info, 0, sizeof(info));
+ info.type = RADIO_RESP_SOLICITED_ACK_EXP;
+ handle_serial = observe_serial = info.serial = 123;
+
+ remote = test_gbinder_servicemanager_new_service(sm, fqname, service.obj);
+ radio = radio_instance_new_with_version(DEV, slot, RADIO_INTERFACE_1_4);
+ id[0] = radio_instance_add_response_handler(radio, TEST_RESP,
+ test_resp_handle, &handle_serial);
+ id[1] = radio_instance_add_response_observer_with_priority(radio,
+ RADIO_INSTANCE_PRIORITY_HIGHEST, TEST_RESP,
+ test_resp_observe1, &observe_serial);
+ id[2] = radio_instance_add_response_observer(radio, TEST_RESP,
+ test_resp_observe2, &observe_serial);
+ id[3] = radio_instance_add_request_observer(radio,
+ RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT, test_resp_ack_observe, &ack_count);
+
+ g_assert(service.resp_obj);
+ resp = gbinder_client_new2(service.resp_obj,
+ TEST_ARRAY_AND_COUNT(radio_resp_iface_info));
+
+ /* Submit broken respose first (without info) */
+ req = gbinder_client_new_request2(resp, TEST_RESP);
+ g_assert_cmpint(gbinder_client_transact_sync_oneway(resp, TEST_RESP, req),
+ == ,GBINDER_STATUS_OK);
+ g_assert_cmpint(ack_count, == ,0);
+ g_assert_cmpint(test_service_req_count(&service,
+ RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,ack_count);
+
+ /* Add the info and try again */
+ gbinder_local_request_init_writer(req, &writer);
+ gbinder_writer_append_buffer_object(&writer, &info, sizeof(info));
+ g_assert_cmpint(gbinder_client_transact_sync_oneway(resp, TEST_RESP, req),
+ == ,GBINDER_STATUS_OK);
+ g_assert_cmpint(ack_count, == ,1);
+ g_assert_cmpint(test_service_req_count(&service,
+ RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,ack_count);
+ g_assert(!handle_serial); /* Cleared by the handler */
+ g_assert(!observe_serial); /* Cleared by the observer */
+
+ /* Remove the handler and check auto-ack */
+ radio_instance_remove_handlers(radio, id, 1);
+ handle_serial = observe_serial = info.serial = 124;
+
+ gbinder_local_request_unref(req);
+ req = gbinder_client_new_request2(resp, TEST_RESP);
+ gbinder_local_request_init_writer(req, &writer);
+ gbinder_writer_append_buffer_object(&writer, &info, sizeof(info));
+
+ g_assert_cmpint(gbinder_client_transact_sync_oneway(resp, TEST_RESP, req),
+ == ,GBINDER_STATUS_OK);
+ g_assert_cmpint(ack_count, == ,2); /* Acked */
+ g_assert_cmpint(test_service_req_count(&service,
+ RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,ack_count);
+ g_assert_cmpuint(handle_serial, == ,info.serial); /* No handler */
+ g_assert(!observe_serial); /* Cleared by the observer */
+
+ /* RADIO_RESP_SOLICITED won't be acked */
+ info.type = RADIO_RESP_SOLICITED;
+ handle_serial = observe_serial = info.serial = 125;
+
+ gbinder_local_request_unref(req);
+ req = gbinder_client_new_request2(resp, TEST_RESP);
+ gbinder_local_request_init_writer(req, &writer);
+ gbinder_writer_append_buffer_object(&writer, &info, sizeof(info));
+
+ g_assert_cmpint(gbinder_client_transact_sync_oneway(resp, TEST_RESP, req),
+ == ,GBINDER_STATUS_OK);
+ g_assert_cmpint(ack_count, == ,2); /* Not acked */
+ g_assert_cmpint(test_service_req_count(&service,
+ RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,ack_count);
+ g_assert_cmpuint(handle_serial, == ,info.serial); /* No handler */
+ g_assert(!observe_serial); /* Cleared by the observer */
+
+ /* Unsupported interface */
+ gbinder_local_request_unref(req);
+ req = test_gbinder_local_request_new("foo");
+ g_assert_cmpint(gbinder_client_transact_sync_oneway(resp, TEST_RESP, req),
+ == ,GBINDER_STATUS_FAILED);
+ g_assert_cmpint(test_service_req_count(&service,
+ RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,2); /* Didn't change */
+
+ gbinder_local_request_unref(req);
+ gbinder_client_unref(resp);
+
+ radio_instance_remove_all_handlers(radio, id);
+ radio_instance_unref(radio);
+ test_service_cleanup(&service);
+ gbinder_remote_object_unref(remote);
+ gbinder_servicemanager_unref(sm);
+}
+
+/*==========================================================================*
+ * ack
+ *==========================================================================*/
+
+static
+void
+test_ack_cb(
+ RadioInstance* radio,
+ guint32 serial,
+ gpointer user_data)
+{
+ guint* expected = user_data;
+
+ GDEBUG("ack %u", serial);
+ g_assert_cmpuint(serial, == ,*expected);
+ *expected = 0;
+}
+
+static
+void
+test_ack(
+ void)
+{
+ const char* slot = "slot1";
+ const char* fqname = RADIO_1_0 "/slot1";
+ TestRadioService service;
+ GBinderServiceManager* sm = gbinder_servicemanager_new(DEV);
+ GBinderRemoteObject* remote;
+ GBinderLocalRequest* req;
+ GBinderClient* resp;
+ RadioInstance* radio;
+ guint serial = 123;
+ gulong id[3];
+
+ test_service_init(&service);
+ remote = test_gbinder_servicemanager_new_service(sm, fqname, service.obj);
+ radio = radio_instance_new_with_version(DEV, slot, RADIO_INTERFACE_1_4);
+ id[0] = radio_instance_add_ack_handler(radio, test_ack_cb, &serial);
+ id[1] = radio_instance_add_response_handler(radio, RADIO_RESP_ANY,
+ test_response_not_handled, NULL);
+ id[2] = radio_instance_add_response_observer(radio,
+ RADIO_RESP_ACKNOWLEDGE_REQUEST, test_response_not_observed, NULL);
+
+ g_assert(service.resp_obj);
+ resp = gbinder_client_new2(service.resp_obj,
+ TEST_ARRAY_AND_COUNT(radio_resp_iface_info));
+
+ /* Submit broken ack first (without serial) */
+ req = gbinder_client_new_request2(resp, RADIO_RESP_ACKNOWLEDGE_REQUEST);
+ g_assert_cmpint(gbinder_client_transact_sync_oneway(resp,
+ RADIO_RESP_ACKNOWLEDGE_REQUEST, req), == ,GBINDER_STATUS_OK);
+ g_assert(serial); /* Transaction succeeds but handler is not called */
+
+ /* Add the serial and try again */
+ gbinder_local_request_append_int32(req, serial);
+ g_assert_cmpint(gbinder_client_transact_sync_oneway(resp,
+ RADIO_RESP_ACKNOWLEDGE_REQUEST, req), == ,GBINDER_STATUS_OK);
+ g_assert(!serial); /* Cleared by the handler */
+ gbinder_local_request_unref(req);
+ gbinder_client_unref(resp);
+
+ radio_instance_remove_all_handlers(radio, id);
+ radio_instance_unref(radio);
+ test_service_cleanup(&service);
+ gbinder_remote_object_unref(remote);
+ gbinder_servicemanager_unref(sm);
+}
+
+/*==========================================================================*
+ * send_req
+ *==========================================================================*/
+
+static
+void
+test_send_req_complete_cb(
+ RadioInstance* instance,
+ gulong id,
+ int status,
+ void* user_data1,
+ void* user_data2)
+{
+ gulong* expected_id = user_data1;
+
+ GDEBUG("tx %lu completed", id);
+ g_assert_cmpuint(id, == ,*expected_id);
+ *expected_id = 0;
+ test_quit_later((GMainLoop*)user_data2);
+}
+
+static
+void
+test_send_req_destroy_cb(
+ void* user_data1,
+ void* user_data2)
+{
+ gulong* id = user_data1;
+
+ GDEBUG("tx %lu done", *id);
+ g_assert(*id);
+ *id = 0;
+ test_quit_later((GMainLoop*)user_data2);
+}
+
+static
+void
+test_send_req_complete_not_reached(
+ RadioInstance* instance,
+ gulong id,
+ int status,
+ void* user_data1,
+ void* user_data2)
+{
+ g_assert_not_reached();
+}
+
+static
+void
+test_send_req_destroy_not_reached(
+ void* user_data1,
+ void* user_data2)
+{
+ g_assert_not_reached();
+}
+
+static
+void
+test_send_req(
+ void)
+{
+ const char* slot = "slot1";
+ const char* fqname = RADIO_1_0 "/slot1";
+ TestRadioService service;
+ GMainLoop* loop = g_main_loop_new(NULL, FALSE);
+ GBinderServiceManager* sm = gbinder_servicemanager_new(DEV);
+ GBinderRemoteObject* remote;
+ GBinderLocalRequest* req;
+ RadioInstance* radio;
+ guint serial = 123;
+ gulong tx;
+
+ test_service_init(&service);
+ remote = test_gbinder_servicemanager_new_service(sm, fqname, service.obj);
+ radio = radio_instance_new_with_version(DEV, slot, RADIO_INTERFACE_1_4);
+
+ /* Submit and wait for the completion callback to be invoked */
+ req = radio_instance_new_request(radio, RADIO_REQ_GET_MUTE);
+ gbinder_local_request_append_int32(req, serial);
+ tx = radio_instance_send_request(radio, RADIO_REQ_GET_MUTE, req,
+ test_send_req_complete_cb, NULL, &tx, loop);
+ gbinder_local_request_unref(req);
+ g_assert(tx);
+ GDEBUG("tx %lu submitted", tx);
+
+ test_run(&test_opt, loop);
+ g_assert(!tx); /* Cleared by the completion handler */
+
+ /* Submit and wait for the destroy callback to be invoked */
+ serial = 124;
+ req = radio_instance_new_request(radio, RADIO_REQ_GET_MUTE);
+ gbinder_local_request_append_int32(req, serial);
+ tx = radio_instance_send_request(radio, RADIO_REQ_GET_MUTE, req,
+ NULL, test_send_req_destroy_cb, &tx, loop);
+ gbinder_local_request_unref(req);
+ g_assert(tx);
+ GDEBUG("tx %lu submitted", tx);
+
+ test_run(&test_opt, loop);
+ g_assert(!tx); /* Cleared by the destroy callback */
+
+ /* Submit, cancel and wait for the destroy callback to be invoked */
+ serial = 125;
+ req = radio_instance_new_request(radio, RADIO_REQ_GET_MUTE);
+ gbinder_local_request_append_int32(req, serial);
+ tx = radio_instance_send_request(radio, RADIO_REQ_GET_MUTE, req,
+ test_send_req_complete_not_reached, test_send_req_destroy_cb,
+ &tx, loop);
+ gbinder_local_request_unref(req);
+ g_assert(tx);
+ GDEBUG("canceling tx %lu and waiting for destroy callback", tx);
+ radio_instance_cancel_request(radio, tx);
+
+ test_run(&test_opt, loop);
+ g_assert(!tx); /* Cleared by the destroy callback */
+
+ /* Submit without callbacks and cancel */
+ req = radio_instance_new_request(radio, RADIO_REQ_GET_MUTE);
+ gbinder_local_request_append_int32(req, serial);
+ tx = radio_instance_send_request(radio, RADIO_REQ_GET_MUTE, req,
+ NULL, NULL, NULL, NULL);
+ gbinder_local_request_unref(req);
+ g_assert(tx);
+ GDEBUG("canceling tx %lu", tx);
+ radio_instance_cancel_request(radio, tx);
+
+ /* radio_instance_send_request() fails if the remote is dead */
+ test_gbinder_remote_object_kill(remote);
+ req = radio_instance_new_request(radio, RADIO_REQ_GET_MUTE);
+ gbinder_local_request_append_int32(req, serial);
+ tx = radio_instance_send_request(radio, RADIO_REQ_GET_MUTE, req,
+ NULL, test_send_req_destroy_not_reached, NULL, NULL);
+ gbinder_local_request_unref(req);
+ g_assert(!tx);
+
+ radio_instance_unref(radio);
+ test_service_cleanup(&service);
+ gbinder_remote_object_unref(remote);
+ gbinder_servicemanager_unref(sm);
+ g_main_loop_unref(loop);
+}
+
+/*==========================================================================*
+ * enabled
+ *==========================================================================*/
+
+static
+void
+test_enabled_cb(
+ RadioInstance* radio,
+ gpointer user_data)
+{
+ GDEBUG("%sabled", radio->enabled ? "En" : "Dis");
+ (*((int*)user_data))++;
+}
+
+static
+void
+test_enabled(
+ void)
+{
+ const char* slot = "slot1";
+ const char* fqname = RADIO_1_0 "/slot1";
+ TestRadioService service;
+ GBinderServiceManager* sm = gbinder_servicemanager_new(DEV);
+ GBinderRemoteObject* remote;
+ RadioInstance* radio;
+ int n = 0;
+ gulong id;
+
+ test_service_init(&service);
+ remote = test_gbinder_servicemanager_new_service(sm, fqname, service.obj);
+ radio = radio_instance_new_with_version(DEV, slot, RADIO_INTERFACE_1_4);
+ id = radio_instance_add_enabled_handler(radio, test_enabled_cb, &n);
+
+ g_assert(id);
+ g_assert(!radio->enabled);
+ radio_instance_set_enabled(radio, TRUE);
+ g_assert_cmpint(n, == ,1);
+ g_assert(radio->enabled);
+
+ radio_instance_set_enabled(radio, TRUE);
+ g_assert(radio->enabled);
+ g_assert_cmpint(n, == ,1); /* Nothing changed */
+
+ radio_instance_set_enabled(radio, FALSE);
+ g_assert_cmpint(n, == ,2);
+ g_assert(!radio->enabled);
+
+ radio_instance_remove_handler(radio, id);
+ radio_instance_unref(radio);
+ test_service_cleanup(&service);
+ gbinder_remote_object_unref(remote);
+ gbinder_servicemanager_unref(sm);
+}
+
+/*==========================================================================*
+ * death
+ *==========================================================================*/
+
+static
+void
+test_death_cb(
+ RadioInstance* radio,
+ gpointer user_data)
+{
+ GDEBUG("Boom");
+ (*((int*)user_data))++;
+}
+
+static
+void
+test_death(
+ void)
+{
+ const char* slot = "slot1";
+ const char* fqname = RADIO_1_0 "/slot1";
+ TestRadioService service;
+ GBinderServiceManager* sm = gbinder_servicemanager_new(DEV);
+ GBinderRemoteObject* remote;
+ RadioInstance* radio;
+ int n = 0;
+ gulong id;
+
+ test_service_init(&service);
+ remote = test_gbinder_servicemanager_new_service(sm, fqname, service.obj);
+ radio = radio_instance_new_with_version(DEV, slot, RADIO_INTERFACE_1_4);
+ id = radio_instance_add_death_handler(radio, test_death_cb, &n);
+
+ g_assert(id);
+ g_assert(!radio_instance_is_dead(radio));
+ test_gbinder_remote_object_kill(remote);
+ g_assert_cmpint(n, == ,1);
+ g_assert(radio_instance_is_dead(radio));
+
+ radio_instance_remove_handler(radio, 0); /* no effect */
+ radio_instance_remove_handler(radio, id);
+ radio_instance_unref(radio);
+ test_service_cleanup(&service);
+ gbinder_remote_object_unref(remote);
+ gbinder_servicemanager_unref(sm);
+}
+
+/*==========================================================================*
+ * Common
+ *==========================================================================*/
+
+#define TEST_PREFIX "/instance/"
+#define TEST_(t) TEST_PREFIX t
+
+int main(int argc, char* argv[])
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_add_func(TEST_("null"), test_null);
+ g_test_add_func(TEST_("basic"), test_basic);
+ g_test_add_func(TEST_("connected"), test_connected);
+ g_test_add_func(TEST_("ind"), test_ind);
+ g_test_add_func(TEST_("req"), test_req);
+ g_test_add_func(TEST_("resp"), test_resp);
+ g_test_add_func(TEST_("ack"), test_ack);
+ g_test_add_func(TEST_("send_req"), test_send_req);
+ g_test_add_func(TEST_("enabled"), test_enabled);
+ g_test_add_func(TEST_("death"), test_death);
+ test_init(&test_opt, argc, argv);
+ return g_test_run();
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/unit_registry/Makefile
^
|
@@ -0,0 +1,5 @@
+# -*- Mode: makefile-gmake -*-
+
+EXE = unit_registry
+
+include ../common/Makefile
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/unit_registry/unit_registry.c
^
|
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2021 Jolla Ltd.
+ * Copyright (C) 2021 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#include "test_common.h"
+
+#include "radio_instance.h"
+#include "radio_registry_p.h"
+
+#include <glib-object.h>
+
+static TestOpt test_opt;
+
+/*==========================================================================*
+ * null
+ *==========================================================================*/
+
+static
+void
+test_null(
+ void)
+{
+ radio_registry_instance_added(NULL);
+ radio_registry_instance_removed(NULL);
+ radio_registry_remove_handler(NULL, 0);
+ radio_registry_remove_handlers(NULL, NULL, 0);
+ radio_registry_unref(NULL);
+ g_assert(!radio_registry_ref(NULL));
+ g_assert(!radio_registry_add_instance_added_handler(NULL,NULL,NULL,NULL));
+ g_assert(!radio_registry_add_instance_removed_handler(NULL,NULL,NULL,NULL));
+}
+
+/*==========================================================================*
+ * basic
+ *==========================================================================*/
+
+static const char* test_basic_key = "foo";
+static const char* test_basic_bad_key = "bar";
+
+static
+void
+test_basic_add_cb(
+ RadioRegistry* registry,
+ RadioInstance* radio,
+ gpointer user_data)
+{
+ (*((int*)user_data))++;
+}
+
+static
+void
+test_basic_remove_cb(
+ RadioRegistry* registry,
+ const char* str,
+ gpointer user_data)
+{
+ g_assert_cmpstr(str, == ,test_basic_key);
+ (*((int*)user_data))++;
+}
+
+static
+void
+test_basic(
+ void)
+{
+ RadioRegistry* reg = radio_registry_new();
+ int add_count = 0, remove_count = 0;
+ gulong id[6];
+ GObject* instance;
+
+ g_assert(reg);
+ g_assert(reg == radio_registry_new()); /* New ref to the same instance */
+ radio_registry_unref(reg);
+
+ g_assert(!radio_registry_add_instance_added_handler(reg,NULL,NULL,NULL));
+ g_assert(!radio_registry_add_instance_removed_handler(reg,NULL,NULL,NULL));
+
+ /* Add/remove handlers */
+ id[0] = radio_registry_add_instance_added_handler(reg, "",
+ test_basic_add_cb, &add_count);
+ radio_registry_remove_handler(reg, id[0]);
+ id[0] = radio_registry_add_instance_added_handler(reg, NULL,
+ test_basic_add_cb, &add_count);
+ id[1] = radio_registry_add_instance_added_handler(reg, test_basic_bad_key,
+ test_basic_add_cb, &add_count); /* won't get called */
+
+ id[2] = radio_registry_add_instance_removed_handler(reg, NULL,
+ test_basic_remove_cb, &remove_count);
+ id[3] = radio_registry_add_instance_removed_handler(reg, "",
+ test_basic_remove_cb, &remove_count);
+ id[4] = radio_registry_add_instance_removed_handler(reg, test_basic_key,
+ test_basic_remove_cb, &remove_count);
+ id[5] = radio_registry_add_instance_removed_handler(reg, test_basic_bad_key,
+ test_basic_remove_cb, &remove_count); /* won't get called */
+
+ /* Well, this wouldn't be a real functional instance but we don't care */
+ instance = g_object_new(RADIO_TYPE_INSTANCE, NULL);
+ radio_registry_instance_added(RADIO_INSTANCE(instance));
+ g_assert_cmpint(add_count, == ,1); /* 1 out of 2 is called */
+ g_assert_cmpint(remove_count, == ,0);
+
+ radio_registry_instance_removed(test_basic_key);
+ g_assert_cmpint(add_count, == ,1);
+ g_assert_cmpint(remove_count, == ,3); /* 3 our of 4 are called */
+ g_object_unref(instance);
+
+ /* remove_all zeros the ids */
+ radio_registry_remove_all_handlers(reg, id);
+ g_assert(!id[0]);
+ g_assert(!id[4]);
+
+ radio_registry_remove_handler(reg, 0); /* No effect */
+ radio_registry_unref(reg);
+}
+
+/*==========================================================================*
+ * Common
+ *==========================================================================*/
+
+#define TEST_PREFIX "/registry/"
+#define TEST_(t) TEST_PREFIX t
+
+int main(int argc, char* argv[])
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_add_func(TEST_("null"), test_null);
+ g_test_add_func(TEST_("basic"), test_basic);
+ test_init(&test_opt, argc, argv);
+ return g_test_run();
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/unit_util/Makefile
^
|
@@ -0,0 +1,5 @@
+# -*- Mode: makefile-gmake -*-
+
+EXE = unit_util
+
+include ../common/Makefile
|
[-]
[+]
|
Added |
_service:tar_git:libgbinder-radio-1.5.4.tar.bz2/unit/unit_util/unit_util.c
^
|
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2022 Jolla Ltd.
+ * Copyright (C) 2022 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of the BSD license as follows:
+ *
+ * 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 names of the copyright holders 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 HOLDERS 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * any official policies, either expressed or implied.
+ */
+
+#include "test_common.h"
+
+#include "radio_util.h"
+
+#define UNKNOWN_VALUE (0x7fffffff)
+#define UNKNOWN_REQ ((RADIO_REQ)UNKNOWN_VALUE)
+#define UNKNOWN_IND ((RADIO_REQ)UNKNOWN_VALUE)
+#define UNKNOWN_RESP ((RADIO_RESP)UNKNOWN_VALUE)
+
+static TestOpt test_opt;
+
+/*==========================================================================*
+ * req_name
+ *==========================================================================*/
+
+static
+void
+test_req_name(
+ void)
+{
+ g_assert(!radio_req_name(UNKNOWN_REQ));
+ g_assert(!radio_req_name(RADIO_REQ_ANY));
+ g_assert_cmpstr(radio_req_name(RADIO_REQ_GET_ICC_CARD_STATUS),==,
+ "getIccCardStatus");
+ g_assert_cmpstr(radio_req_name(RADIO_REQ_START_NETWORK_SCAN),==,
+ "startNetworkScan");
+ g_assert_cmpstr(radio_req_name(RADIO_REQ_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA),==,
+ "setSignalStrengthReportingCriteria");
+ g_assert_cmpstr(radio_req_name(RADIO_REQ_SET_SYSTEM_SELECTION_CHANNELS),==,
+ "setSystemSelectionChannels");
+ g_assert_cmpstr(radio_req_name(RADIO_REQ_EMERGENCY_DIAL),==,
+ "emergencyDial");
+ g_assert_cmpstr(radio_req_name(RADIO_REQ_ENABLE_UICC_APPLICATIONS),==,
+ "enableUiccApplications");
+ g_assert_cmpstr(radio_req_name(RADIO_REQ_START_NETWORK_SCAN_1_4),==,
+ "startNetworkScan_1_4");
+ g_assert_cmpstr(radio_req_name(RADIO_REQ_START_NETWORK_SCAN_1_5),==,
+ "startNetworkScan_1_5");
+}
+
+/*==========================================================================*
+ * resp_name
+ *==========================================================================*/
+
+static
+void
+test_resp_name(
+ void)
+{
+ g_assert(!radio_resp_name(UNKNOWN_RESP));
+ g_assert(!radio_resp_name(RADIO_RESP_ANY));
+ g_assert_cmpstr(radio_resp_name(RADIO_RESP_GET_ICC_CARD_STATUS),==,
+ "getIccCardStatusResponse");
+ g_assert_cmpstr(radio_resp_name(RADIO_RESP_START_NETWORK_SCAN),==,
+ "startNetworkScanResponse");
+ g_assert_cmpstr(radio_resp_name(RADIO_RESP_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA),==,
+ "setSignalStrengthReportingCriteriaResponse");
+ g_assert_cmpstr(radio_resp_name(RADIO_RESP_SET_SYSTEM_SELECTION_CHANNELS),==,
+ "setSystemSelectionChannelsResponse");
+ g_assert_cmpstr(radio_resp_name(RADIO_RESP_EMERGENCY_DIAL),==,
+ "emergencyDialResponse");
+ g_assert_cmpstr(radio_resp_name(RADIO_RESP_ENABLE_UICC_APPLICATIONS),==,
+ "enableUiccApplicationsResponse");
+ g_assert_cmpstr(radio_resp_name(RADIO_RESP_START_NETWORK_SCAN_1_4),==,
+ "startNetworkScanResponse_1_4");
+ g_assert_cmpstr(radio_resp_name(RADIO_RESP_START_NETWORK_SCAN_1_5),==,
+ "startNetworkScanResponse_1_5");
+}
+
+/*==========================================================================*
+ * ind_name
+ *==========================================================================*/
+
+static
+void
+test_ind_name(
+ void)
+{
+ g_assert(!radio_ind_name(UNKNOWN_IND));
+ g_assert(!radio_ind_name(RADIO_IND_ANY));
+ g_assert_cmpstr(radio_ind_name(RADIO_IND_RADIO_STATE_CHANGED),==,
+ "radioStateChanged");
+ g_assert_cmpstr(radio_ind_name(RADIO_IND_NETWORK_SCAN_RESULT),==,
+ "networkScanResult");
+ g_assert_cmpstr(radio_ind_name(RADIO_IND_CURRENT_LINK_CAPACITY_ESTIMATE),==,
+ "currentLinkCapacityEstimate");
+ g_assert_cmpstr(radio_ind_name(RADIO_IND_CURRENT_EMERGENCY_NUMBER_LIST),==,
+ "currentEmergencyNumberList");
+ g_assert_cmpstr(radio_ind_name(RADIO_IND_REGISTRATION_FAILED),==,
+ "registrationFailed");
+}
+
+/*==========================================================================*
+ * req_resp
+ *==========================================================================*/
+
+static
+void
+test_req_resp(
+ void)
+{
+ static const struct radio_req_resp_data {
+ RADIO_REQ req;
+ RADIO_RESP resp;
+ } tests[] = {
+ { UNKNOWN_REQ, RADIO_RESP_NONE },
+ { RADIO_REQ_ANY, RADIO_RESP_NONE },
+ { RADIO_REQ_SETUP_DATA_CALL_1_2, RADIO_RESP_SETUP_DATA_CALL },
+ { RADIO_REQ_DEACTIVATE_DATA_CALL_1_2, RADIO_RESP_DEACTIVATE_DATA_CALL },
+ { RADIO_REQ_START_NETWORK_SCAN_1_2, RADIO_RESP_START_NETWORK_SCAN },
+ { RADIO_REQ_SET_INITIAL_ATTACH_APN_1_4,
+ RADIO_RESP_SET_INITIAL_ATTACH_APN },
+ { RADIO_REQ_SET_DATA_PROFILE_1_4, RADIO_RESP_SET_DATA_PROFILE },
+ { RADIO_REQ_SET_INDICATION_FILTER_1_2,
+ RADIO_RESP_SET_INDICATION_FILTER },
+ { RADIO_REQ_GET_ICC_CARD_STATUS, RADIO_RESP_GET_ICC_CARD_STATUS },
+ { RADIO_REQ_START_NETWORK_SCAN, RADIO_RESP_START_NETWORK_SCAN },
+ { RADIO_REQ_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA,
+ RADIO_RESP_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA },
+ { RADIO_REQ_SET_SYSTEM_SELECTION_CHANNELS,
+ RADIO_RESP_SET_SYSTEM_SELECTION_CHANNELS },
+ { RADIO_REQ_EMERGENCY_DIAL, RADIO_RESP_EMERGENCY_DIAL }
+ };
+
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS(tests); i++) {
+ g_assert_cmpint(radio_req_resp(tests[i].req), ==, tests[i].resp);
+ }
+}
+
+/*==========================================================================*
+ * req_resp2
+ *==========================================================================*/
+
+static
+void
+test_req_resp2(
+ void)
+{
+ static const struct radio_req_resp2_data {
+ RADIO_REQ req;
+ RADIO_INTERFACE iface;
+ RADIO_RESP resp;
+ } tests[] = {
+ { UNKNOWN_REQ, RADIO_INTERFACE_NONE, RADIO_RESP_NONE },
+ { RADIO_REQ_SUPPLY_ICC_PIN_FOR_APP, RADIO_INTERFACE_1_0,
+ RADIO_RESP_SUPPLY_ICC_PIN_FOR_APP },
+ { RADIO_REQ_SUPPLY_ICC_PUK_FOR_APP, RADIO_INTERFACE_1_1,
+ RADIO_RESP_SUPPLY_ICC_PUK_FOR_APP },
+ { RADIO_REQ_SUPPLY_ICC_PIN2_FOR_APP, RADIO_INTERFACE_1_2,
+ RADIO_RESP_SUPPLY_ICC_PIN2_FOR_APP },
+ { RADIO_REQ_SUPPLY_ICC_PUK2_FOR_APP, RADIO_INTERFACE_1_3,
+ RADIO_RESP_SUPPLY_ICC_PUK2_FOR_APP },
+ { RADIO_REQ_CHANGE_ICC_PIN_FOR_APP, RADIO_INTERFACE_1_4,
+ RADIO_RESP_CHANGE_ICC_PIN_FOR_APP },
+ { RADIO_REQ_CHANGE_ICC_PIN2_FOR_APP, RADIO_INTERFACE_COUNT,
+ RADIO_RESP_CHANGE_ICC_PIN2_FOR_APP },
+
+ { RADIO_REQ_SETUP_DATA_CALL_1_2, RADIO_INTERFACE_1_2,
+ RADIO_RESP_SETUP_DATA_CALL },
+ { RADIO_REQ_SETUP_DATA_CALL_1_2, RADIO_INTERFACE_1_4,
+ RADIO_RESP_SETUP_DATA_CALL },
+
+ { RADIO_REQ_DEACTIVATE_DATA_CALL_1_2, RADIO_INTERFACE_1_2,
+ RADIO_RESP_DEACTIVATE_DATA_CALL },
+ { RADIO_REQ_DEACTIVATE_DATA_CALL_1_2, RADIO_INTERFACE_1_4,
+ RADIO_RESP_DEACTIVATE_DATA_CALL },
+
+ { RADIO_REQ_START_NETWORK_SCAN_1_2, RADIO_INTERFACE_1_2,
+ RADIO_RESP_START_NETWORK_SCAN },
+ { RADIO_REQ_START_NETWORK_SCAN_1_2, RADIO_INTERFACE_1_4,
+ RADIO_RESP_START_NETWORK_SCAN },
+
+ { RADIO_REQ_SET_INITIAL_ATTACH_APN_1_4, RADIO_INTERFACE_1_4,
+ RADIO_RESP_SET_INITIAL_ATTACH_APN },
+
+ { RADIO_REQ_SET_DATA_PROFILE_1_4, RADIO_INTERFACE_1_4,
+ RADIO_RESP_SET_DATA_PROFILE },
+
+ { RADIO_REQ_SET_INDICATION_FILTER_1_2, RADIO_INTERFACE_1_2,
+ RADIO_RESP_SET_INDICATION_FILTER },
+ { RADIO_REQ_SET_INDICATION_FILTER_1_2, RADIO_INTERFACE_1_4,
+ RADIO_RESP_SET_INDICATION_FILTER },
+ { RADIO_REQ_SET_INDICATION_FILTER_1_5, RADIO_INTERFACE_1_5,
+ RADIO_RESP_SET_INDICATION_FILTER_1_5 },
+
+
+ { RADIO_REQ_GET_ICC_CARD_STATUS, RADIO_INTERFACE_1_0,
+ RADIO_RESP_GET_ICC_CARD_STATUS },
+ { RADIO_REQ_GET_ICC_CARD_STATUS, RADIO_INTERFACE_1_1,
+ RADIO_RESP_GET_ICC_CARD_STATUS },
+ { RADIO_REQ_GET_ICC_CARD_STATUS, RADIO_INTERFACE_1_2,
+ RADIO_RESP_GET_ICC_CARD_STATUS_1_2 },
+ { RADIO_REQ_GET_ICC_CARD_STATUS, RADIO_INTERFACE_1_3,
+ RADIO_RESP_GET_ICC_CARD_STATUS_1_2 },
+ { RADIO_REQ_GET_ICC_CARD_STATUS, RADIO_INTERFACE_1_4,
+ RADIO_RESP_GET_ICC_CARD_STATUS_1_4 },
+ { RADIO_REQ_GET_ICC_CARD_STATUS, RADIO_INTERFACE_1_5,
+ RADIO_RESP_GET_ICC_CARD_STATUS_1_5 },
+ { RADIO_REQ_GET_ICC_CARD_STATUS, RADIO_INTERFACE_COUNT,
+ RADIO_RESP_NONE },
+ { RADIO_REQ_GET_ICC_CARD_STATUS, RADIO_INTERFACE_NONE,
+ RADIO_RESP_NONE },
+
+ { RADIO_REQ_GET_CELL_INFO_LIST, RADIO_INTERFACE_1_0,
+ RADIO_RESP_GET_CELL_INFO_LIST },
+ { RADIO_REQ_GET_CELL_INFO_LIST, RADIO_INTERFACE_1_1,
+ RADIO_RESP_GET_CELL_INFO_LIST },
+ { RADIO_REQ_GET_CELL_INFO_LIST, RADIO_INTERFACE_1_2,
+ RADIO_RESP_GET_CELL_INFO_LIST_1_2 },
+ { RADIO_REQ_GET_CELL_INFO_LIST, RADIO_INTERFACE_1_3,
+ RADIO_RESP_GET_CELL_INFO_LIST_1_2 },
+ { RADIO_REQ_GET_CELL_INFO_LIST, RADIO_INTERFACE_1_4,
+ RADIO_RESP_GET_CELL_INFO_LIST_1_4 },
+ { RADIO_REQ_GET_CELL_INFO_LIST, RADIO_INTERFACE_1_5,
+ RADIO_RESP_GET_CELL_INFO_LIST_1_5 },
+ { RADIO_REQ_GET_CELL_INFO_LIST, RADIO_INTERFACE_COUNT,
+ RADIO_RESP_GET_CELL_INFO_LIST_1_5 },
+ { RADIO_REQ_GET_CELL_INFO_LIST, RADIO_INTERFACE_NONE,
+ RADIO_RESP_NONE },
+
+ { RADIO_REQ_GET_CURRENT_CALLS, RADIO_INTERFACE_1_0,
+ RADIO_RESP_GET_CURRENT_CALLS },
+ { RADIO_REQ_GET_CURRENT_CALLS, RADIO_INTERFACE_1_1,
+ RADIO_RESP_GET_CURRENT_CALLS },
+ { RADIO_REQ_GET_CURRENT_CALLS, RADIO_INTERFACE_1_2,
+ RADIO_RESP_GET_CURRENT_CALLS_1_2 },
+ { RADIO_REQ_GET_CURRENT_CALLS, RADIO_INTERFACE_1_3,
+ RADIO_RESP_GET_CURRENT_CALLS_1_2 },
+ { RADIO_REQ_GET_CURRENT_CALLS, RADIO_INTERFACE_1_4,
+ RADIO_RESP_GET_CURRENT_CALLS_1_2 },
+ { RADIO_REQ_GET_CURRENT_CALLS, RADIO_INTERFACE_COUNT,
+ RADIO_RESP_GET_CURRENT_CALLS_1_2 },
+ { RADIO_REQ_GET_CURRENT_CALLS, RADIO_INTERFACE_NONE,
+ RADIO_RESP_NONE },
+
+ { RADIO_REQ_GET_SIGNAL_STRENGTH, RADIO_INTERFACE_1_0,
+ RADIO_RESP_GET_SIGNAL_STRENGTH },
+ { RADIO_REQ_GET_SIGNAL_STRENGTH, RADIO_INTERFACE_1_1,
+ RADIO_RESP_GET_SIGNAL_STRENGTH },
+ { RADIO_REQ_GET_SIGNAL_STRENGTH, RADIO_INTERFACE_1_2,
+ RADIO_RESP_GET_SIGNAL_STRENGTH_1_2 },
+ { RADIO_REQ_GET_SIGNAL_STRENGTH, RADIO_INTERFACE_1_3,
+ RADIO_RESP_GET_SIGNAL_STRENGTH_1_2 },
+ { RADIO_REQ_GET_SIGNAL_STRENGTH, RADIO_INTERFACE_1_4,
+ RADIO_RESP_GET_SIGNAL_STRENGTH_1_2 },
+ { RADIO_REQ_GET_SIGNAL_STRENGTH, RADIO_INTERFACE_COUNT,
+ RADIO_RESP_GET_SIGNAL_STRENGTH_1_2 },
+ { RADIO_REQ_GET_SIGNAL_STRENGTH, RADIO_INTERFACE_NONE,
+ RADIO_RESP_NONE },
+
+ { RADIO_REQ_GET_VOICE_REGISTRATION_STATE, RADIO_INTERFACE_1_0,
+ RADIO_RESP_GET_VOICE_REGISTRATION_STATE },
+ { RADIO_REQ_GET_VOICE_REGISTRATION_STATE, RADIO_INTERFACE_1_1,
+ RADIO_RESP_GET_VOICE_REGISTRATION_STATE },
+ { RADIO_REQ_GET_VOICE_REGISTRATION_STATE, RADIO_INTERFACE_1_2,
+ RADIO_RESP_GET_VOICE_REGISTRATION_STATE_1_2 },
+ { RADIO_REQ_GET_VOICE_REGISTRATION_STATE, RADIO_INTERFACE_1_3,
+ RADIO_RESP_GET_VOICE_REGISTRATION_STATE_1_2 },
+ { RADIO_REQ_GET_VOICE_REGISTRATION_STATE, RADIO_INTERFACE_1_4,
+ RADIO_RESP_GET_VOICE_REGISTRATION_STATE_1_2 },
+ { RADIO_REQ_GET_VOICE_REGISTRATION_STATE, RADIO_INTERFACE_COUNT,
+ RADIO_RESP_GET_VOICE_REGISTRATION_STATE_1_2 },
+ { RADIO_REQ_GET_VOICE_REGISTRATION_STATE, RADIO_INTERFACE_NONE,
+ RADIO_RESP_NONE },
+
+ { RADIO_REQ_GET_DATA_REGISTRATION_STATE, RADIO_INTERFACE_1_0,
+ RADIO_RESP_GET_DATA_REGISTRATION_STATE },
+ { RADIO_REQ_GET_DATA_REGISTRATION_STATE, RADIO_INTERFACE_1_1,
+ RADIO_RESP_GET_DATA_REGISTRATION_STATE },
+ { RADIO_REQ_GET_DATA_REGISTRATION_STATE, RADIO_INTERFACE_1_2,
+ RADIO_RESP_GET_DATA_REGISTRATION_STATE_1_2 },
+ { RADIO_REQ_GET_DATA_REGISTRATION_STATE, RADIO_INTERFACE_1_3,
+ RADIO_RESP_GET_DATA_REGISTRATION_STATE_1_2 },
+ { RADIO_REQ_GET_DATA_REGISTRATION_STATE, RADIO_INTERFACE_1_4,
+ RADIO_RESP_GET_DATA_REGISTRATION_STATE_1_4 },
+ { RADIO_REQ_GET_DATA_REGISTRATION_STATE, RADIO_INTERFACE_COUNT,
+ RADIO_RESP_GET_DATA_REGISTRATION_STATE_1_4 },
+ { RADIO_REQ_GET_DATA_REGISTRATION_STATE, RADIO_INTERFACE_NONE,
+ RADIO_RESP_NONE },
+
+ { RADIO_REQ_GET_DATA_CALL_LIST, RADIO_INTERFACE_1_0,
+ RADIO_RESP_GET_DATA_CALL_LIST },
+ { RADIO_REQ_GET_DATA_CALL_LIST, RADIO_INTERFACE_1_1,
+ RADIO_RESP_GET_DATA_CALL_LIST },
+ { RADIO_REQ_GET_DATA_CALL_LIST, RADIO_INTERFACE_1_2,
+ RADIO_RESP_GET_DATA_CALL_LIST },
+ { RADIO_REQ_GET_DATA_CALL_LIST, RADIO_INTERFACE_1_3,
+ RADIO_RESP_GET_DATA_CALL_LIST },
+ { RADIO_REQ_GET_DATA_CALL_LIST, RADIO_INTERFACE_1_4,
+ RADIO_RESP_GET_DATA_CALL_LIST_1_4 },
+ { RADIO_REQ_GET_DATA_CALL_LIST, RADIO_INTERFACE_1_5,
+ RADIO_RESP_GET_DATA_CALL_LIST_1_5 },
+ { RADIO_REQ_GET_DATA_CALL_LIST, RADIO_INTERFACE_COUNT,
+ RADIO_RESP_GET_DATA_CALL_LIST_1_5 },
+ { RADIO_REQ_GET_DATA_CALL_LIST, RADIO_INTERFACE_NONE,
+ RADIO_RESP_NONE }
+ };
+
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS(tests); i++) {
+ g_assert_cmpint(radio_req_resp2(tests[i].req, tests[i].iface), ==,
+ tests[i].resp);
+ }
+}
+
+/*==========================================================================*
+ * Common
+ *==========================================================================*/
+
+#define TEST_PREFIX "/util/"
+#define TEST_(t) TEST_PREFIX t
+
+int main(int argc, char* argv[])
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_add_func(TEST_("req_name"), test_req_name);
+ g_test_add_func(TEST_("resp_name"), test_resp_name);
+ g_test_add_func(TEST_("ind_name"), test_ind_name);
+ g_test_add_func(TEST_("req_resp"), test_req_resp);
+ g_test_add_func(TEST_("req_resp2"), test_req_resp2);
+ test_init(&test_opt, argc, argv);
+ return g_test_run();
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|