[gbinder-radio] Add RadioClient and related APIs. JB#55524

Replacement of some gint32 fields with enums may cause "warning:
passing argument xxx from incompatible pointer type" or something
similar at compile time but it's safe from the ABI prospective
because those enums have the same size as gint32 (and that's
checked at compiled time). It may, however, cause compilation
errors in the projects compiled with -Werror
This commit is contained in:
Slava Monich
2021-09-26 18:53:16 +03:00
parent 6a9a0b7d5e
commit 24a5e281d7
30 changed files with 6280 additions and 140 deletions

View File

@@ -47,8 +47,11 @@ LIB = $(LIB_NAME).a
#
SRC = \
radio_client.c \
radio_instance.c \
radio_registry.c \
radio_request.c \
radio_request_group.c \
radio_util.c
#

2
README Normal file
View File

@@ -0,0 +1,2 @@
A library for communicating with Android IRadio binder services,
built on top of libgbinder.

143
include/radio_client.h Normal file
View File

@@ -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:
*/

View File

@@ -45,15 +45,6 @@ G_BEGIN_DECLS
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,14 +58,30 @@ struct radio_instance {
gboolean enabled;
/* Since 1.2.0 */
RADIO_INTERFACE version;
/* Since 1.4.3 */
gboolean connected; /* rilConnected received */
};
typedef enum radio_instance_priority {
RADIO_INSTANCE_PRIORITY_LOWEST,
RADIO_INSTANCE_PRIORITY_DEFAULT = 2,
RADIO_INSTANCE_PRIORITY_HIGHEST = 7
} RADIO_INSTANCE_PRIORITY; /* Since 1.4.3 */
typedef
void
(*RadioInstanceFunc)(
RadioInstance* radio,
gpointer user_data);
typedef
void
(*RadioRequestObserverFunc)(
RadioInstance* radio,
RADIO_REQ code,
GBinderLocalRequest* args,
gpointer user_data); /* Since 1.4.3 */
typedef
gboolean
(*RadioResponseHandlerFunc)(
@@ -172,6 +179,11 @@ void
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,12 +220,35 @@ radio_instance_set_enabled(
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_INSTANCE_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_INSTANCE_PRIORITY priority,
RADIO_RESP code,
RadioResponseObserverFunc func,
gpointer user_data); /* Since 1.4.3 */
gulong
radio_instance_add_indication_observer(
RadioInstance* radio,
@@ -221,6 +256,14 @@ radio_instance_add_indication_observer(
RadioIndicationObserverFunc func,
gpointer user_data);
gulong
radio_instance_add_indication_observer_with_priority(
RadioInstance* radio,
RADIO_INSTANCE_PRIORITY priority,
RADIO_IND code,
RadioIndicationObserverFunc func,
gpointer user_data); /* Since 1.4.3 */
gulong
radio_instance_add_response_handler(
RadioInstance* radio,
@@ -229,10 +272,10 @@ radio_instance_add_response_handler(
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 @@ radio_instance_add_enabled_handler(
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,

198
include/radio_request.h Normal file
View File

@@ -0,0 +1,198 @@
/*
* 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_H
#define RADIO_REQUEST_H
/* This API exists since 1.4.3 */
#include <radio_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
*
* Invoked upon completion of each request. If an error occurs,
* resp is set to RADIO_RESP_NONE (zero) 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);
/*
* 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,
RADIO_RESP resp,
RADIO_ERROR error,
const GBinderReader* args,
void* user_data);
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)
G_GNUC_WARN_UNUSED_RESULT;
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)
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);
G_END_DECLS
#endif /* RADIO_REQUEST_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -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:
*/

View File

@@ -42,8 +42,27 @@
G_BEGIN_DECLS
typedef struct radio_client RadioClient;
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_COUNT
} RADIO_INTERFACE; /* Since 1.2.0 */
#define RADIO_IFACE_PREFIX "android.hardware.radio@"
#define RADIO_IFACE "IRadio"
@@ -74,6 +93,94 @@ typedef struct radio_registry RadioRegistry;
#define RADIO_ALIGNED(x) __attribute__ ((aligned(x)))
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_resp_type {
RADIO_RESP_SOLICITED,
RADIO_RESP_SOLICITED_ACK,
@@ -182,6 +289,7 @@ typedef enum 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),
@@ -402,10 +510,548 @@ typedef enum radio_scan_status {
} RADIO_SCAN_STATUS; /* Since 1.2.5 */
G_STATIC_ASSERT(sizeof(RADIO_SCAN_STATUS) == 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_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);
@@ -480,13 +1126,13 @@ G_STATIC_ASSERT(sizeof(RadioCall_1_2) == 96);
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);
@@ -542,10 +1188,10 @@ typedef struct radio_data_profile_1_4 {
G_STATIC_ASSERT(sizeof(RadioDataProfile_1_4) == 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 +1203,10 @@ typedef struct radio_data_call {
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> */
@@ -625,7 +1271,7 @@ typedef struct radio_icc_io_result {
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);
@@ -1018,7 +1664,7 @@ typedef struct radio_cell_info_nr {
G_STATIC_ASSERT(sizeof(RadioCellInfoNr) == 112);
typedef struct radio_cell_info_1_4 {
guint32 registered RADIO_ALIGNED(1);
guint8 registered RADIO_ALIGNED(1);
guint32 connectionStatus RADIO_ALIGNED(4);
guint8 cellInfoType RADIO_ALIGNED(1); /* RADIO_CELL_INFO_TYPE_1_4 */
union {
@@ -1045,7 +1691,7 @@ typedef struct radio_select_uicc_sub {
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 +1714,7 @@ G_STATIC_ASSERT(sizeof(RadioSimRefresh) == 24);
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,7 +1759,7 @@ G_STATIC_ASSERT(sizeof(RadioHardwareConfigSim) == 16);
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_4> */
} RADIO_ALIGNED(8) RadioNetworkScanResult; /* Since 1.2.5 */
@@ -1410,15 +2056,27 @@ typedef enum radio_resp {
/* 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_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_RESP_SETUP_DATA_CALL_1_4 = 155,
RADIO_1_4_RESP_LAST = RADIO_RESP_GET_SIGNAL_STRENGTH_1_4
#undef RADIO_RESP_
} RADIO_RESP;
/* 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
typedef enum radio_ind {
RADIO_IND_ANY = 0,
RADIO_IND_NONE = 0,
@@ -1462,4 +2120,3 @@ G_END_DECLS
* indent-tabs-mode: nil
* End:
*/

View File

@@ -7,8 +7,8 @@ License: BSD
URL: https://github.com/mer-hybris/libgbinder-radio
Source: %{name}-%{version}.tar.bz2
%define libgbinder_version 1.0.9
%define libglibutil_version 1.0.34
%define libgbinder_version 1.1.14
%define libglibutil_version 1.0.49
BuildRequires: pkgconfig
BuildRequires: pkgconfig(glib-2.0)

1141
src/radio_client.c Normal file

File diff suppressed because it is too large Load Diff

121
src/radio_client_p.h Normal file
View File

@@ -0,0 +1,121 @@
/*
* 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_PRIVATE_H
#define RADIO_CLIENT_PRIVATE_H
#include "radio_types_p.h"
#include "radio_client.h"
#include <glib-object.h>
struct radio_client {
GObject object;
RadioInstance* instance;
};
void
radio_client_register_request(
RadioClient* client,
RadioRequest* req)
RADIO_INTERNAL;
void
radio_client_unregister_request(
RadioClient* client,
RadioRequest* req)
RADIO_INTERNAL;
gboolean
radio_client_submit_request(
RadioClient* client,
RadioRequest* req)
RADIO_INTERNAL;
gboolean
radio_client_retry_request(
RadioClient* client,
RadioRequest* req)
RADIO_INTERNAL;
void
radio_client_request_dropped(
RadioRequest* req)
RADIO_INTERNAL;
guint
radio_client_timeout_ms(
RadioClient* client,
RadioRequest* req)
RADIO_INTERNAL;
void
radio_client_reset_timeout(
RadioClient* client)
RADIO_INTERNAL;
void
radio_client_reset_timeout(
RadioClient* client)
RADIO_INTERNAL;
RADIO_BLOCK
radio_client_block_status(
RadioClient* client,
RadioRequestGroup* group)
RADIO_INTERNAL;
RADIO_BLOCK
radio_client_block(
RadioClient* client,
RadioRequestGroup* group)
RADIO_INTERNAL;
void
radio_client_unblock(
RadioClient* client,
RadioRequestGroup* group)
RADIO_INTERNAL;
#endif /* RADIO_CLIENT_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -36,7 +36,7 @@
#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_log.h"
@@ -44,6 +44,7 @@
#include <gbinder.h>
#include <gutil_idlepool.h>
#include <gutil_macros.h>
#include <gutil_misc.h>
#include <gutil_strv.h>
@@ -56,6 +57,7 @@ struct radio_instance_priv {
GBinderRemoteObject* remote;
GBinderLocalObject* response;
GBinderLocalObject* indication;
GHashTable* req_quarks;
GHashTable* resp_quarks;
GHashTable* ind_quarks;
gulong death_id;
@@ -67,24 +69,59 @@ struct radio_instance_priv {
G_DEFINE_TYPE(RadioInstance, radio_instance, G_TYPE_OBJECT)
enum radio_instance_signal {
SIGNAL_HANDLE_INDICATION,
G_STATIC_ASSERT(RADIO_INSTANCE_PRIORITY_LOWEST == 0);
G_STATIC_ASSERT(RADIO_INSTANCE_PRIORITY_HIGHEST == 7);
#define FOREACH_PRIORITY(p) p(0) p(1) p(2) p(3) p(4) p(5) p(6) p(7)
#define RADIO_INSTANCE_PRIORITY_INDEX(p) ((p) - RADIO_INSTANCE_PRIORITY_LOWEST)
#define RADIO_INSTANCE_PRIORITY_COUNT \
(RADIO_INSTANCE_PRIORITY_INDEX(RADIO_INSTANCE_PRIORITY_HIGHEST) + 1)
typedef enum radio_instance_signal {
#define SIGNAL_INDEX(x) SIGNAL_OBSERVE_REQUEST_##x,
FOREACH_PRIORITY(SIGNAL_INDEX)
#undef SIGNAL_INDEX
#define SIGNAL_INDEX(x) SIGNAL_OBSERVE_RESPONSE_##x,
FOREACH_PRIORITY(SIGNAL_INDEX)
#undef SIGNAL_INDEX
#define SIGNAL_INDEX(x) SIGNAL_OBSERVE_INDICATION_##x,
FOREACH_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_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_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_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 };
@@ -144,32 +181,41 @@ static const RadioInterfaceDesc radio_interfaces[] = {
};
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;
@@ -202,6 +248,42 @@ radio_instance_resp_quark(
return q;
}
static
guint
radio_instance_priority_index(
RADIO_INSTANCE_PRIORITY priority)
{
if (priority < RADIO_INSTANCE_PRIORITY_LOWEST) {
return 0;
} else if (priority > RADIO_INSTANCE_PRIORITY_HIGHEST) {
return RADIO_INSTANCE_PRIORITY_COUNT - 1;
} else {
return priority - RADIO_INSTANCE_PRIORITY_LOWEST;
}
}
static
void
radio_instance_notify_request_observers(
RadioInstance* self,
RADIO_REQ code,
GBinderLocalRequest* args)
{
GQuark quark = 0;
int i;
for (i = RADIO_INSTANCE_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(
@@ -224,15 +306,49 @@ radio_instance_indication(
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_INSTANCE_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_INSTANCE_PRIORITY_DEFAULT; p--) {
if (signals[RADIO_INSTANCE_PRIORITY_INDEX(p)]) {
g_signal_emit(self, signals
[RADIO_INSTANCE_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_INSTANCE_PRIORITY_LOWEST; p--) {
if (signals[RADIO_INSTANCE_PRIORITY_INDEX(p)]) {
g_signal_emit(self, signals
[RADIO_INSTANCE_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);
@@ -283,15 +399,36 @@ radio_instance_response(
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_INSTANCE_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_INSTANCE_PRIORITY_DEFAULT; p--) {
if (signals[RADIO_INSTANCE_PRIORITY_INDEX(p)]) {
g_signal_emit(self, signals
[RADIO_INSTANCE_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_INSTANCE_PRIORITY_LOWEST; p--) {
if (signals[RADIO_INSTANCE_PRIORITY_INDEX(p)]) {
g_signal_emit(self, signals
[RADIO_INSTANCE_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);
@@ -354,6 +491,7 @@ radio_instance_died(
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);
@@ -479,6 +617,124 @@ radio_instance_make_key(
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
*==========================================================================*/
@@ -645,6 +901,22 @@ radio_instance_unref(
}
}
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,
@@ -714,8 +986,11 @@ radio_instance_ack(
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;
}
@@ -738,8 +1013,10 @@ radio_instance_send_request_sync(
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;
}
@@ -757,57 +1034,153 @@ radio_instance_set_enabled(
}
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_INSTANCE_PRIORITY_DEFAULT, code, func, user_data);
}
gulong
radio_instance_add_request_observer_with_priority(
RadioInstance* self,
RADIO_INSTANCE_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_instance_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_INSTANCE_PRIORITY_DEFAULT, code, func, user_data);
}
gulong
radio_instance_add_response_observer_with_priority(
RadioInstance* self,
RADIO_INSTANCE_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_instance_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_INSTANCE_PRIORITY_DEFAULT, code, func, user_data);
}
gulong
radio_instance_add_indication_observer_with_priority(
RadioInstance* self,
RADIO_INSTANCE_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_instance_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;
}
@@ -841,6 +1214,16 @@ radio_instance_add_enabled_handler(
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,
@@ -874,6 +1257,7 @@ radio_instance_init(
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);
}
@@ -889,6 +1273,7 @@ radio_instance_finalize(
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);
@@ -909,24 +1294,17 @@ radio_instance_class_init(
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,
@@ -939,6 +1317,10 @@ radio_instance_class_init(
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);
}
/*

89
src/radio_instance_p.h Normal file
View File

@@ -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:
*/

View File

@@ -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 @@ struct radio_registry {
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 @@ radio_registry_new(
(gpointer*)(&radio_registry_instance));
}
return radio_registry_instance;
}
RadioRegistry*

View File

@@ -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 */

342
src/radio_request.c Normal file
View File

@@ -0,0 +1,342 @@
/*
* 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 "radio_request_p.h"
#include "radio_request_group_p.h"
#include "radio_instance_p.h"
#include "radio_client_p.h"
#include "radio_log.h"
#include <gbinder_local_request.h>
#include <gbinder_writer.h>
#include <gutil_macros.h>
typedef struct radio_request_object {
RadioRequest pub;
RadioInstance* instance;
GDestroyNotify destroy;
gsize serial_offset;
gboolean dropped;
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;
if (req->tx_id) {
radio_instance_cancel_request(self->instance, req->tx_id);
req->tx_id = 0;
}
if (!self->dropped) {
self->dropped = TRUE;
radio_request_group_remove(req->group, req);
radio_client_request_dropped(req);
}
radio_client_unregister_request(req->client, req);
}
static
void
radio_request_free(
RadioRequestObject* self)
{
RadioRequest* req = &self->pub;
radio_request_object_cancel(self);
if (req->complete) {
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);
radio_instance_unref(self->instance);
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)
{
return status != RADIO_TX_STATUS_OK || error != RADIO_ERROR_NONE;
}
static
RadioRequest*
radio_request_object_new(
RadioClient* client,
RadioRequestGroup* group,
RADIO_REQ code,
GBinderWriter* writer,
RadioRequestCompleteFunc complete,
GDestroyNotify destroy,
void* user_data)
{
RadioRequestObject* self = g_slice_new0(RadioRequestObject);
RadioRequest* req = &self->pub;
GBinderWriter tmp;
self->instance = radio_instance_ref(client->instance);
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_client_register_request(client, req);
radio_request_group_add(group, req);
/* Build the argument list */
if (!writer) writer = &tmp;
req->args = radio_instance_new_request(client->instance, 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(client, NULL, code,
writer, 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(group->client, group, code,
writer, 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) {
RadioClient* client = req->client;
req->timeout_ms = ms;
if (client && req->state >= RADIO_REQUEST_STATE_QUEUED) {
const uint timeout = radio_client_timeout_ms(client, req);
req->deadline = g_get_monotonic_time() + MICROSEC(timeout);
radio_client_reset_timeout(client);
}
}
}
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)
{
return req && req->client && radio_client_submit_request(req->client, req);
}
gboolean
radio_request_retry(
RadioRequest* req)
{
return req && req->client && radio_client_retry_request(req->client, 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);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

224
src/radio_request_group.c Normal file
View File

@@ -0,0 +1,224 @@
/*
* 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 "radio_request_group_p.h"
#include "radio_request_p.h"
#include "radio_client_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;
RadioClient* client = group->client;
radio_client_unblock(client, group);
g_hash_table_destroy(self->requests);
radio_client_unref(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_client_block_status(group->client, group) :
RADIO_BLOCK_NONE;
}
RADIO_BLOCK
radio_request_group_block(
RadioRequestGroup* group)
{
return group ? radio_client_block(group->client, group) :
RADIO_BLOCK_NONE;
}
void
radio_request_group_unblock(
RadioRequestGroup* group)
{
if (group) {
radio_client_unblock(group->client, group);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -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:
*/

151
src/radio_request_p.h Normal file
View File

@@ -0,0 +1,151 @@
/*
* 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_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;
struct radio_request {
RADIO_REQUEST_STATE state;
RADIO_REQ code;
GBinderLocalRequest* args;
RadioRequestCompleteFunc 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 */
gulong tx_id; /* Id of the request transaction */
gboolean blocking; /* TRUE if this request blocks all others */
gboolean acked;
RadioClient* client; /* 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:
*/

55
src/radio_types_p.h Normal file
View File

@@ -0,0 +1,55 @@
/*
* 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_TYPES_PRIVATE_H
#define RADIO_TYPES_PRIVATE_H
#include <radio_types.h>
#define RADIO_INTERNAL G_GNUC_INTERNAL
/* Miliseconds to microseconds */
#define MICROSEC(ms) (((gint64)(ms)) * 1000)
#endif /* RADIO_TYPES_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -1,7 +1,10 @@
# -*- Mode: makefile-gmake -*-
.PHONY: clean all
all:
%:
@$(MAKE) -C unit_client $*
@$(MAKE) -C unit_instance $*
@$(MAKE) -C unit_registry $*
@$(MAKE) -C unit_util $*

View File

@@ -1,7 +1,8 @@
# -*- Mode: makefile-gmake -*-
.PHONY: clean all debug release coverage
.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.
@@ -62,11 +63,9 @@ LD = $(CC)
WARNINGS += -Wall -Wno-deprecated-declarations
INCLUDES += -I$(COMMON_DIR) -I$(LIB_DIR)/src -I$(LIB_DIR)/include
BASE_FLAGS = -fPIC
BASE_LDFLAGS = $(BASE_FLAGS) $(LDFLAGS)
BASE_CFLAGS = $(BASE_FLAGS) $(CFLAGS)
FULL_CFLAGS = $(BASE_CFLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) -MMD -MP \
$(shell pkg-config --cflags $(PKGS))
FULL_LDFLAGS = $(BASE_LDFLAGS)
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

View File

@@ -41,7 +41,7 @@ typedef struct test_gbinder_data TestGBinderData;
TestGBinderData*
test_gbinder_data_new(
void);
const char* iface);
TestGBinderData*
test_gbinder_data_ref(

View File

@@ -50,6 +50,7 @@ typedef struct test_gbinder_client_tx {
typedef struct test_gbinder_client_iface_range {
char* iface;
GBytes* header;
guint32 last_code;
} TestGBinderClientIfaceRange;
@@ -68,7 +69,10 @@ test_gbinder_client_free(
guint i;
for (i = 0; i < self->nr; i++) {
g_free(self->ranges[i].iface);
TestGBinderClientIfaceRange* r = self->ranges + i;
g_bytes_unref(r->header);
g_free(r->iface);
}
g_free(self->ranges);
gbinder_remote_object_unref(self->remote);
@@ -81,6 +85,7 @@ 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;
}
@@ -183,7 +188,9 @@ test_gbinder_client_tx_handle(
GBinderRemoteReply* reply = test_gbinder_client_transact
(tx->client, tx->code, tx->flags, tx->req, &status);
tx->reply(tx->client, reply, status, tx->user_data);
if (tx->reply) {
tx->reply(tx->client, reply, status, tx->user_data);
}
gbinder_remote_reply_unref(reply);
return G_SOURCE_REMOVE;
}
@@ -262,6 +269,22 @@ gbinder_client_unref(
}
}
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,
@@ -354,7 +377,9 @@ gbinder_client_cancel(
GBinderClient* self,
gulong id)
{
g_source_remove((guint)id);
if (id) {
g_source_remove((guint)id);
}
}
/*

View File

@@ -63,7 +63,7 @@ test_gbinder_local_reply_new(
GBinderLocalReply* self = g_new0(GBinderLocalReply, 1);
g_atomic_int_set(&self->refcount, 1);
self->data = test_gbinder_data_new();
self->data = test_gbinder_data_new(NULL);
return self;
}

View File

@@ -64,7 +64,7 @@ test_gbinder_local_request_new(
g_assert(iface);
g_atomic_int_set(&self->refcount, 1);
self->data = test_gbinder_data_new();
self->data = test_gbinder_data_new(iface);
self->iface = g_strdup(iface);
return self;
}

View File

@@ -36,9 +36,11 @@
#include "test_gbinder.h"
#include <gutil_macros.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
@@ -49,9 +51,10 @@ struct test_gbinder_data_item {
TestGBinderDataItem* next;
DATA_TYPE type;
union {
gboolean b;
gint32 i32;
struct {
const void* buf;
void* buf;
gsize size;
} blob;
GBinderLocalObject* obj;
@@ -62,6 +65,8 @@ struct test_gbinder_data_item {
struct test_gbinder_data {
guint32 refcount;
TestGBinderDataItem* items;
GUtilIdlePool* pool;
char* iface;
};
typedef struct test_gbinder_reader {
@@ -87,6 +92,15 @@ test_gbinder_data_item_destroy_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(
@@ -118,6 +132,8 @@ 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);
}
@@ -155,17 +171,111 @@ test_gbinder_data_append(
}
}
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;
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(
void)
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;
}
@@ -208,9 +318,11 @@ test_gbinder_data_init_writer(
TestGBinderData* data,
GBinderWriter* writer)
{
memset(writer, 0, sizeof(*writer));
if (data) {
test_gbinder_writer_cast(writer)->data = data;
if (writer) {
memset(writer, 0, sizeof(*writer));
if (data) {
test_gbinder_writer_cast(writer)->data = data;
}
}
}
@@ -274,6 +386,33 @@ gbinder_reader_read_object(
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,
@@ -286,6 +425,29 @@ gbinder_writer_append_int32(
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,
@@ -296,7 +458,8 @@ gbinder_writer_append_buffer_object(
TestGBinderDataItem* item = test_gbinder_data_item_new(DATA_TYPE_BUFFER);
const guint index = test_gbinder_data_count_buffers(self->data);
item->data.blob.buf = buf;
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;

View File

@@ -4,6 +4,7 @@
#
TESTS="\
unit_client \
unit_instance \
unit_registry \
unit_util"

View File

@@ -0,0 +1,5 @@
# -*- Mode: makefile-gmake -*-
EXE = unit_client
include ../common/Makefile

File diff suppressed because it is too large Load Diff

View File

@@ -37,7 +37,7 @@
#include "test_common.h"
#include "test_gbinder.h"
#include "radio_instance.h"
#include "radio_instance_p.h"
#include "radio_util.h"
#include <gutil_strv.h>
@@ -216,9 +216,9 @@ test_null(
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));
@@ -229,10 +229,13 @@ test_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));
@@ -240,9 +243,11 @@ test_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));
}
/*==========================================================================*
@@ -262,6 +267,7 @@ test_basic(
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));
@@ -279,10 +285,20 @@ test_basic(
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));
@@ -290,6 +306,7 @@ test_basic(
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), == ,
@@ -317,6 +334,147 @@ test_basic(
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;
ulong 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
*==========================================================================*/
@@ -446,7 +604,7 @@ test_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);
@@ -460,6 +618,20 @@ test_ind(
#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(
@@ -472,14 +644,32 @@ test_req(
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);
@@ -496,7 +686,22 @@ test_req(
static
void
test_resp_observe(
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,
@@ -505,11 +710,27 @@ test_resp_observe(
{
guint* expected = user_data;
GDEBUG("Observing resp %u", code);
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(
@@ -546,7 +767,8 @@ test_resp(
RadioResponseInfo info;
GBinderWriter writer;
guint handle_serial, observe_serial;
gulong id[2];
int ack_count = 0;
gulong id[4];
test_service_init(&service);
@@ -558,8 +780,13 @@ test_resp(
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(radio, TEST_RESP,
test_resp_observe, &observe_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,
@@ -569,36 +796,52 @@ test_resp(
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), == ,0);
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), == ,1);
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), == ,2); /* Acked */
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), == ,2); /* Not acked */
RADIO_REQ_RESPONSE_ACKNOWLEDGEMENT), == ,ack_count);
g_assert_cmpuint(handle_serial, == ,info.serial); /* No handler */
g_assert(!observe_serial); /* Cleared by the observer */
@@ -688,6 +931,148 @@ test_ack(
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
*==========================================================================*/
@@ -801,10 +1186,12 @@ 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);