[-]
[+]
|
Changed |
_service:tar_git:nfcd-binder-plugin.changes
|
|
[-]
[+]
|
Changed |
_service:tar_git:nfcd-binder-plugin.spec
^
|
|
[-]
[+]
|
Changed |
_service
^
|
@@ -2,7 +2,7 @@
<service name="tar_git">
<param name="url">https://github.com/mer-hybris/nfcd-binder-plugin.git</param>
<param name="branch">master</param>
- <param name="revision"></param>
+ <param name="revision">b40fa70caa52ec984c18204ce7f87a1d916ecf36</param>
<param name="token"/>
<param name="debian">N</param>
<param name="dumb">N</param>
|
[-]
[+]
|
Changed |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/Makefile
^
|
@@ -1,12 +1,13 @@
# -*- Mode: makefile-gmake -*-
-.PHONY: clean all debug release install
+.PHONY: clean all release
+.PHONY: nci_debug_lib nci_release_lib
#
# Required packages
#
-LDPKGS = libncicore libgbinder libglibutil gobject-2.0 glib-2.0
+LDPKGS = libgbinder libglibutil gobject-2.0 glib-2.0
PKGS = $(LDPKGS) nfcd-plugin
#
@@ -25,6 +26,16 @@
LIB = $(LIB_SONAME)
#
+# libnfc-nci
+#
+
+NCI_LIB = libnci.a
+NCI_DIR = nci
+NCI_BUILD_DIR = $(NCI_DIR)/build
+NCI_DEBUG_LIB = $(NCI_BUILD_DIR)/debug/$(NCI_LIB)
+NCI_RELEASE_LIB = $(NCI_BUILD_DIR)/release/$(NCI_LIB)
+
+#
# Sources
#
@@ -42,6 +53,10 @@
DEBUG_BUILD_DIR = $(BUILD_DIR)/debug
RELEASE_BUILD_DIR = $(BUILD_DIR)/release
+NCI_DIR = nci
+NCI_SRC_DIR = $(NCI_DIR)/src
+NCI_CFLAGS = -I$(NCI_SRC_DIR)
+
#
# Tools and flags
#
@@ -52,7 +67,7 @@
BASE_FLAGS = -fPIC -fvisibility=hidden
DEFINES = -DNFC_PLUGIN_EXTERNAL
FULL_CFLAGS = $(BASE_FLAGS) $(CFLAGS) $(DEFINES) $(WARNINGS) -MMD -MP \
- $(shell pkg-config --cflags $(PKGS))
+ -I$(NCI_DIR)/include $(shell pkg-config --cflags $(PKGS))
FULL_LDFLAGS = $(BASE_FLAGS) $(LDFLAGS) -shared
DEBUG_FLAGS = -g
RELEASE_FLAGS =
@@ -71,15 +86,19 @@
RELEASE_CFLAGS = $(FULL_CFLAGS) $(RELEASE_FLAGS) -O2
LIBS = $(shell pkg-config --libs $(LDPKGS))
-DEBUG_LIBS = $(LIBS)
-RELEASE_LIBS = $(LIBS)
+DEBUG_LIBS = $(NCI_DEBUG_LIB) $(LIBS)
+RELEASE_LIBS = $(NCI_RELEASE_LIB) $(LIBS)
#
# Files
#
-DEBUG_OBJS = $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
-RELEASE_OBJS = $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
+DEBUG_OBJS = \
+ $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o) \
+ $(NCI_SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
+RELEASE_OBJS = \
+ $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o) \
+ $(NCI_SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
#
# Dependencies
@@ -94,9 +113,11 @@
endif
endif
-DEBUG_DEPS =
-RELEASE_DEPS =
+DEBUG_DEPS = $(NCI_DEBUG_LIB)
+RELEASE_DEPS = $(NCI_RELEASE_LIB)
+$(NCI_DEBUG_LIB): | nci_debug_lib
+$(NCI_RELEASE_LIB): | nci_release_lib
$(DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
$(RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
@@ -107,14 +128,21 @@
DEBUG_LIB = $(DEBUG_BUILD_DIR)/$(LIB)
RELEASE_LIB = $(RELEASE_BUILD_DIR)/$(LIB)
-debug: $(DEBUG_LIB)
+debug: nci_debug_lib $(DEBUG_LIB)
-release: $(RELEASE_LIB)
+release: nci_release_lib $(RELEASE_LIB)
clean:
+ make -C $(NCI_DIR) clean
rm -f *~ rpm/*~ $(SRC_DIR)/*~
rm -fr $(BUILD_DIR)
+nci_debug_lib:
+ make -C $(NCI_DIR) debug
+
+nci_release_lib:
+ make -C $(NCI_DIR) release
+
$(DEBUG_BUILD_DIR):
mkdir -p $@
@@ -127,6 +155,12 @@
$(RELEASE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
$(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
+$(DEBUG_BUILD_DIR)/%.o : $(NCI_SRC_DIR)/%.c
+ $(CC) -c $(NCI_CFLAGS) $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
+
+$(RELEASE_BUILD_DIR)/%.o : $(NCI_SRC_DIR)/%.c
+ $(CC) -c $(NCI_CFLAGS) $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
+
$(DEBUG_LIB): $(DEBUG_OBJS) $(DEBUG_DEPS)
$(LD) $(DEBUG_OBJS) $(DEBUG_LDFLAGS) $(DEBUG_LIBS) -o $@
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/Makefile
^
|
@@ -0,0 +1,180 @@
+# -*- Mode: makefile-gmake -*-
+
+.PHONY: clean all debug release
+.PHONY: print_debug_lib print_release_lib
+.PHONY: print_debug_path print_release_path
+
+#
+# Required packages
+#
+
+PKGS = libglibutil glib-2.0 gobject-2.0
+
+#
+# Default target
+#
+
+all: debug release
+
+#
+# Library name
+#
+
+NAME = nci
+LIB_NAME = lib$(NAME)
+LIB = $(LIB_NAME).a
+
+#
+# Sources
+#
+
+SRC = \
+ nci_core.c \
+ nci_param.c \
+ nci_param_w4_all_discoveries.c \
+ nci_param_w4_host_select.c \
+ nci_sar.c \
+ nci_sm.c \
+ nci_state.c \
+ nci_state_discovery.c \
+ nci_state_poll_active.c \
+ nci_state_w4_all_discoveries.c \
+ nci_state_w4_host_select.c \
+ nci_transition.c \
+ nci_transition_deactivate_to_idle.c \
+ nci_transition_idle_to_discovery.c \
+ nci_transition_poll_active_to_discovery.c \
+ nci_transition_poll_active_to_idle.c \
+ nci_transition_reset.c \
+ nci_util.c
+
+#
+# Directories
+#
+
+SRC_DIR = src
+INCLUDE_DIR = include
+BUILD_DIR = build
+DEBUG_BUILD_DIR = $(BUILD_DIR)/debug
+RELEASE_BUILD_DIR = $(BUILD_DIR)/release
+COVERAGE_BUILD_DIR = $(BUILD_DIR)/coverage
+
+#
+# Tools and flags
+#
+
+CC = $(CROSS_COMPILE)gcc
+LD = $(CC)
+WARNINGS = -Wall -Wstrict-aliasing -Wunused-result
+INCLUDES = -I$(INCLUDE_DIR)
+BASE_FLAGS = -fPIC
+FULL_CFLAGS = $(BASE_FLAGS) $(CFLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) \
+ -MMD -MP $(shell pkg-config --cflags $(PKGS))
+DEBUG_FLAGS = -g
+RELEASE_FLAGS =
+COVERAGE_FLAGS = -g
+
+ifndef KEEP_SYMBOLS
+KEEP_SYMBOLS = 0
+endif
+
+ifneq ($(KEEP_SYMBOLS),0)
+RELEASE_FLAGS += -g
+endif
+
+DEBUG_CFLAGS = $(FULL_CFLAGS) $(DEBUG_FLAGS) -DDEBUG
+RELEASE_CFLAGS = $(FULL_CFLAGS) $(RELEASE_FLAGS) -O2
+COVERAGE_CFLAGS = $(FULL_CFLAGS) $(COVERAGE_FLAGS) --coverage
+
+#
+# Files
+#
+
+DEBUG_OBJS = $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
+RELEASE_OBJS = $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
+COVERAGE_OBJS = $(SRC:%.c=$(COVERAGE_BUILD_DIR)/%.o)
+
+#
+# Dependencies
+#
+
+DEPS = $(DEBUG_OBJS:%.o=%.d) $(RELEASE_OBJS:%.o=%.d)
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(strip $(DEPS)),)
+-include $(DEPS)
+endif
+endif
+
+$(DEBUG_OBJS) $(DEBUG_LIB): | $(DEBUG_BUILD_DIR)
+$(RELEASE_OBJS) $(RELEASE_LIB): | $(RELEASE_BUILD_DIR)
+$(COVERAGE_OBJS) $(COVERAGE_LIB): | $(COVERAGE_BUILD_DIR)
+
+#
+# Rules
+#
+
+DEBUG_LIB = $(DEBUG_BUILD_DIR)/$(LIB)
+RELEASE_LIB = $(RELEASE_BUILD_DIR)/$(LIB)
+COVERAGE_LIB = $(COVERAGE_BUILD_DIR)/$(LIB)
+
+debug: $(DEBUG_LIB)
+
+release: $(RELEASE_LIB)
+
+debug_lib: $(DEBUG_LIB)
+
+release_lib: $(RELEASE_LIB)
+
+coverage_lib: $(COVERAGE_LIB)
+
+print_debug_lib:
+ @echo $(DEBUG_LIB)
+
+print_release_lib:
+ @echo $(RELEASE_LIB)
+
+print_coverage_lib:
+ @echo $(COVERAGE_LIB)
+
+print_debug_path:
+ @echo $(DEBUG_BUILD_DIR)
+
+print_release_path:
+ @echo $(RELEASE_BUILD_DIR)
+
+clean:
+ rm -f *~ $(SRC_DIR)/*~ $(INCLUDE_DIR)/*~ $(INCLUDE_DIR)/internal/*~
+ rm -fr $(BUILD_DIR)
+
+$(BUILD_DIR):
+ mkdir -p $@
+
+$(DEBUG_BUILD_DIR):
+ mkdir -p $@
+
+$(RELEASE_BUILD_DIR):
+ mkdir -p $@
+
+$(COVERAGE_BUILD_DIR):
+ mkdir -p $@
+
+$(DEBUG_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
+ $(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
+
+$(RELEASE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
+ $(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
+
+$(COVERAGE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
+ $(CC) -c $(COVERAGE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
+
+$(DEBUG_LIB): $(DEBUG_OBJS)
+ $(AR) rc $@ $?
+ ranlib $@
+
+$(RELEASE_LIB): $(RELEASE_OBJS)
+ $(AR) rc $@ $?
+ ranlib $@
+
+$(COVERAGE_LIB): $(COVERAGE_OBJS)
+ $(AR) rc $@ $?
+ ranlib $@
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/include/nci_core.h
^
|
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2018-2019 Jolla Ltd.
+ * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NCI_CORE_H
+#define NCI_CORE_H
+
+#include <nci_types.h>
+
+G_BEGIN_DECLS
+
+/*
+ * If current_state != next_state, the state machine is transitioning
+ * from one state to another. That may take a while.
+ */
+
+typedef struct nci_core {
+ NCI_STATE current_state;
+ NCI_STATE next_state;
+ guint cmd_timeout;
+} NciCore;
+
+typedef
+void
+(*NciCoreFunc)(
+ NciCore* nci,
+ void* user_data);
+
+typedef
+void
+(*NciCoreSendFunc)(
+ NciCore* nci,
+ gboolean success,
+ void* user_data);
+
+typedef
+void
+(*NciCoreDataPacketFunc)(
+ NciCore* nci,
+ guint8 cid,
+ const void* payload,
+ guint len,
+ void* user_data);
+
+typedef
+void
+(*NciCoreIntfActivationFunc)(
+ NciCore* nci,
+ const NciIntfActivationNtf* ntf,
+ void* user_data);
+
+NciCore*
+nci_core_new(
+ NciHalIo* io);
+
+void
+nci_core_free(
+ NciCore* nci);
+
+void
+nci_core_restart(
+ NciCore* nci);
+
+void
+nci_core_set_state(
+ NciCore* nci,
+ NCI_STATE state);
+
+guint
+nci_core_send_data_msg(
+ NciCore* nci,
+ guint8 cid,
+ GBytes* payload,
+ NciCoreSendFunc complete,
+ GDestroyNotify destroy,
+ void* user_data);
+
+void
+nci_core_cancel(
+ NciCore* nci,
+ guint id);
+
+gulong
+nci_core_add_current_state_changed_handler(
+ NciCore* nci,
+ NciCoreFunc func,
+ void* user_data);
+
+gulong
+nci_core_add_next_state_changed_handler(
+ NciCore* nci,
+ NciCoreFunc func,
+ void* user_data);
+
+gulong
+nci_core_add_intf_activated_handler(
+ NciCore* nci,
+ NciCoreIntfActivationFunc func,
+ void* user_data);
+
+gulong
+nci_core_add_data_packet_handler(
+ NciCore* nci,
+ NciCoreDataPacketFunc func,
+ void* user_data);
+
+void
+nci_core_remove_handler(
+ NciCore* nci,
+ gulong id);
+
+void
+nci_core_remove_handlers(
+ NciCore* nci,
+ gulong* ids,
+ guint count);
+
+#define nci_core_remove_all_handlers(core,ids) \
+ nci_core_remove_handlers(core, ids, G_N_ELEMENTS(ids))
+
+G_END_DECLS
+
+#endif /* NCI_CORE_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/include/nci_hal.h
^
|
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018-2019 Jolla Ltd.
+ * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NCI_HAL_H
+#define NCI_HAL_H
+
+#include <nci_types.h>
+
+/* Hardware abstraction layer */
+
+/* Functions provided by HAL implementation */
+
+typedef
+void
+(*NciHalClientFunc)(
+ NciHalClient* client,
+ gboolean ok);
+
+typedef struct nci_hal_io_functions {
+ gboolean (*start)(NciHalIo* io, NciHalClient* client);
+ void (*stop)(NciHalIo* io); /* implicitely cancels write */
+ gboolean (*write)(NciHalIo* io, const GUtilData* chunks, guint count,
+ NciHalClientFunc complete);
+ void (*cancel_write)(NciHalIo* io);
+} NciHalIoFunctions;
+
+struct nci_hal_io {
+ const NciHalIoFunctions* fn;
+};
+
+/* Functions provided by NCI core */
+
+typedef struct nci_hal_client_functions {
+ void (*error)(NciHalClient* client);
+ void (*read)(NciHalClient* client, const void* data, guint len);
+} NciHalClientFunctions;
+
+struct nci_hal_client {
+ const NciHalClientFunctions* fn;
+};
+
+#endif /* NFC_HAL_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/include/nci_state.h
^
|
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NCI_STATE_H
+#define NCI_STATE_H
+
+#include "nci_types.h"
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct nci_state_priv NciStatePriv;
+
+struct nci_state {
+ GObject object;
+ NciStatePriv* priv;
+ NCI_STATE state;
+ const char* name;
+ gboolean active;
+};
+
+GType nci_state_get_type(void);
+#define NCI_TYPE_STATE (nci_state_get_type())
+#define NCI_STATE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ NCI_TYPE_STATE, NciState))
+
+NciState*
+nci_state_ref(
+ NciState* state);
+
+void
+nci_state_unref(
+ NciState* state);
+
+G_END_DECLS
+
+#endif /* NCI_STATE_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/include/nci_types.h
^
|
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2018-2019 Jolla Ltd.
+ * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NCI_TYPES_H
+#define NCI_TYPES_H
+
+#include <gutil_types.h>
+
+G_BEGIN_DECLS
+
+/* Types */
+
+typedef struct nci_core NciCore;
+typedef struct nci_hal_client NciHalClient;
+typedef struct nci_hal_io NciHalIo;
+typedef struct nci_state NciState;
+
+/* Table 4: Conn ID
+ * 0: Static RF Connection between the DH and a Remote NFC Endpoint */
+#define NCI_STATIC_RF_CONN_ID (0x00)
+
+/* Table 94: Status Codes */
+typedef enum nci_status {
+ NCI_STATUS_OK = 0x00,
+ NCI_STATUS_REJECTED = 0x01,
+ NCI_STATUS_RF_FRAME_CORRUPTED = 0x02,
+ NCI_STATUS_FAILED = 0x03,
+ NCI_STATUS_NOT_INITIALIZED = 0x04,
+ NCI_STATUS_SYNTAX_ERROR = 0x05,
+ NCI_STATUS_SEMANTIC_ERROR = 0x06,
+ NCI_STATUS_INVALID_PARAM = 0x09,
+ NCI_STATUS_MESSAGE_SIZE_EXCEEDED = 0x0A,
+ NCI_STATUS_DISCOVERY_ALREADY_STARTED = 0xA0,
+ NCI_STATUS_DISCOVERY_TARGET_ACTIVATION_FAILED = 0xA1,
+ NCI_STATUS_DISCOVERY_TEAR_DOWN = 0xA2,
+ NCI_STATUS_RF_TRANSMISSION_ERROR = 0xB0,
+ NCI_STATUS_RF_PROTOCOL_ERROR = 0xB1,
+ NCI_STATUS_RF_TIMEOUT_ERROR = 0xB2,
+ NCI_STATUS_NFCEE_INTERFACE_ACTIVATION_FAILED = 0xC0,
+ NCI_STATUS_NFCEE_TRANSMISSION_ERROR = 0xC1,
+ NCI_STATUS_NFCEE_PROTOCOL_ERROR = 0xC2,
+ NCI_STATUS_NFCEE_TIMEOUT_ERROR = 0xC3
+} NCI_STATUS;
+
+/* Table 96: RF Technology and Mode */
+typedef enum nci_mode {
+ NCI_MODE_PASSIVE_POLL_A = 0x00,
+ NCI_MODE_PASSIVE_POLL_B = 0x01,
+ NCI_MODE_PASSIVE_POLL_F = 0x02,
+ NCI_MODE_ACTIVE_POLL_A = 0x03,
+ NCI_MODE_ACTIVE_POLL_F = 0x05,
+ NCI_MODE_PASSIVE_POLL_15693 = 0x06,
+ NCI_MODE_PASSIVE_LISTEN_A = 0x80,
+ NCI_MODE_PASSIVE_LISTEN_B = 0x81,
+ NCI_MODE_PASSIVE_LISTEN_F = 0x82,
+ NCI_MODE_ACTIVE_LISTEN_A = 0x83,
+ NCI_MODE_ACTIVE_LISTEN_F = 0x85,
+ NCI_MODE_PASSIVE_LISTEN_15693 = 0x86
+} NCI_MODE;
+
+/* Table 97: Bit Rates */
+typedef enum nci_bit_rate {
+ NFC_BIT_RATE_106 = 0x00, /* 106 Kbit/s */
+ NFC_BIT_RATE_212 = 0x01, /* 212 Kbit/s */
+ NFC_BIT_RATE_424 = 0x02, /* 424 Kbit/s */
+ NFC_BIT_RATE_848 = 0x03, /* 848 Kbit/s */
+ NFC_BIT_RATE_1695 = 0x04, /* 1695 Kbit/s */
+ NFC_BIT_RATE_3390 = 0x05, /* 3390 Kbit/s */
+ NFC_BIT_RATE_6780 = 0x06 /* 6780 Kbit/s */
+} NFC_BIT_RATE;
+
+/* Table 98: RF Protocols */
+typedef enum nci_protocol {
+ NCI_PROTOCOL_UNDETERMINED = 0x00,
+ NCI_PROTOCOL_T1T = 0x01,
+ NCI_PROTOCOL_T2T = 0x02,
+ NCI_PROTOCOL_T3T = 0x03,
+ NCI_PROTOCOL_ISO_DEP = 0x04,
+ NCI_PROTOCOL_NFC_DEP = 0x05,
+} NCI_PROTOCOL;
+
+/* Table 99: RF Interfaces */
+typedef enum nci_rf_interface {
+ NCI_RF_INTERFACE_NFCEE_DIRECT = 0x00,
+ NCI_RF_INTERFACE_FRAME = 0x01,
+ NCI_RF_INTERFACE_ISO_DEP = 0x02,
+ NCI_RF_INTERFACE_NFC_DEP = 0x03
+} NCI_RF_INTERFACE;
+
+/* See Table 54: Specific Parameters for NFC-A Poll Mode */
+typedef struct nci_mode_param_poll_a {
+ guint8 sens_res[2];
+ guint8 nfcid1_len;
+ guint8 nfcid1[10];
+ guint8 sel_res_len;
+ guint8 sel_res;
+} NciModeParamPollA;
+
+/* Table 56: Specific Parameters for NFC-B Poll Mode */
+typedef struct nci_mode_param_poll_b {
+ guint8 nfcid0[4];
+ guint fsc; /* FSCI converted to bytes */
+} NciModeParamPollB;
+
+typedef union nci_mode_param {
+ NciModeParamPollA poll_a;
+ NciModeParamPollB poll_b;
+} NciModeParam;
+
+/* Table 76: Activation Parameters for NFC-A/ISO-DEP Poll Mode */
+typedef struct nci_activation_param_iso_dep_poll_a {
+ guint fsc; /* FSC (FSCI converted to bytes) */
+ GUtilData t1; /* T1 to Tk (otherwise called historical bytes) */
+} NciActivationParamIsoDepPollA;
+
+typedef union nci_activation_param {
+ NciActivationParamIsoDepPollA iso_dep_poll_a;
+} NciActivationParam;
+
+/* See Table 61: Notification for RF Interface activation */
+typedef struct nci_intf_activated_ntf {
+ guint8 discovery_id;
+ NCI_RF_INTERFACE rf_intf;
+ NCI_PROTOCOL protocol;
+ NCI_MODE mode;
+ guint8 max_data_packet_size;
+ guint8 num_credits;
+ guint8 mode_param_len;
+ const void* mode_param_bytes;
+ const NciModeParam* mode_param;
+ NCI_MODE data_exchange_mode;
+ NFC_BIT_RATE transmit_rate;
+ NFC_BIT_RATE receive_rate;
+ guint8 activation_param_len;
+ const void* activation_param_bytes;
+ const NciActivationParam* activation_param;
+} NciIntfActivationNtf;
+
+/* Table 52: Control Messages to Start Discovery */
+typedef struct nci_discovery_ntf {
+ guint8 discovery_id;
+ NCI_PROTOCOL protocol;
+ NCI_MODE mode;
+ guint8 param_len;
+ const void* param_bytes;
+ const NciModeParam* param;
+ gboolean last;
+} NciDiscoveryNtf;
+
+/* NCI states */
+
+typedef enum nci_state_id {
+ NCI_STATE_INIT,
+ NCI_STATE_ERROR,
+ NCI_STATE_STOP,
+ /* RFST states are taken from the NCI spec */
+ NCI_RFST_IDLE,
+ NCI_RFST_DISCOVERY,
+ NCI_RFST_W4_ALL_DISCOVERIES,
+ NCI_RFST_W4_HOST_SELECT,
+ NCI_RFST_POLL_ACTIVE,
+ NCI_RFST_LISTEN_ACTIVE,
+ NCI_RFST_LISTEN_SLEEP,
+ NCI_CORE_STATES
+} NCI_STATE;
+
+/* Logging */
+
+#define NCI_LOG_MODULE nci_log
+extern GLogModule NCI_LOG_MODULE;
+
+G_END_DECLS
+
+#endif /* NFC_TYPES_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_core.c
^
|
@@ -0,0 +1,739 @@
+/*
+ * Copyright (C) 2018-2019 Jolla Ltd.
+ * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "nci_core.h"
+#include "nci_sar.h"
+#include "nci_sm.h"
+#include "nci_state.h"
+#include "nci_log.h"
+
+#include <gutil_misc.h>
+#include <gutil_macros.h>
+
+#include <glib-object.h>
+
+GLOG_MODULE_DEFINE("nci");
+
+typedef struct nci_core_closure {
+ GCClosure cclosure;
+ NciCoreFunc func;
+ gpointer* user_data;
+} NciCoreClosure;
+
+typedef struct nci_core_intf_activated_closure {
+ GCClosure cclosure;
+ NciCoreIntfActivationFunc func;
+ gpointer* user_data;
+} NciCoreIntfActivationClosure;
+
+typedef struct nci_core_data_packet_closure {
+ GCClosure cclosure;
+ NciCoreDataPacketFunc func;
+ gpointer* user_data;
+} NciCoreDataPacketClosure;
+
+typedef struct nci_core_send_data {
+ NciCoreSendFunc complete;
+ GDestroyNotify destroy;
+ gpointer user_data;
+} NciCoreSendData;
+
+enum nci_core_events {
+ EVENT_LAST_STATE,
+ EVENT_NEXT_STATE,
+ EVENT_INTF_ACTIVATED,
+ EVENT_COUNT
+};
+
+typedef struct nci_core_object {
+ GObject object;
+ NciCore core;
+ NciSarClient sar_client;
+ NciSmIo io;
+ NciSm* sm;
+ guint cmd_id;
+ guint cmd_timeout_id;
+ guint8 rsp_gid;
+ guint8 rsp_oid;
+ NciSmResponseFunc rsp_handler;
+ gpointer rsp_data;
+ gulong event_ids[EVENT_COUNT];
+} NciCoreObject;
+
+typedef GObjectClass NciCoreObjectClass;
+G_DEFINE_TYPE(NciCoreObject, nci_core_object, G_TYPE_OBJECT)
+#define NCI_TYPE_CORE (nci_core_object_get_type())
+#define NCI_CORE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ NCI_TYPE_CORE, NciCoreObject))
+
+typedef enum nci_core_signal {
+ SIGNAL_CURRENT_STATE,
+ SIGNAL_NEXT_STATE,
+ SIGNAL_INTF_ACTIVATED,
+ SIGNAL_DATA_PACKET,
+ SIGNAL_COUNT
+} NCI_CORE_SIGNAL;
+
+#define SIGNAL_CURRENT_STATE_NAME "nci-core-current-state"
+#define SIGNAL_NEXT_STATE_NAME "nci-core-next-state"
+#define SIGNAL_INTF_ACTIVATED_NAME "nci-core-intf-activated"
+#define SIGNAL_DATA_PACKET_NAME "nci-core-data-packet"
+
+static guint nci_core_signals[SIGNAL_COUNT] = { 0 };
+
+#define DEFAULT_TIMEOUT (2000) /* msec */
+
+static inline NciCoreObject* nci_core_object(NciCore* ptr)
+{ return G_LIKELY(ptr) ? /* This one should be NULL safe */
+ NCI_CORE(G_CAST(ptr, NciCoreObject, core)) : NULL; }
+
+static inline NciCoreObject* nci_core_object_from_sar_client(NciSarClient* ptr)
+ { return NCI_CORE(G_CAST(ptr, NciCoreObject, sar_client)); }
+
+static inline NciCoreObject* nci_core_object_from_sm_io(NciSmIo* ptr)
+ { return NCI_CORE(G_CAST(ptr, NciCoreObject, io)); }
+
+/*==========================================================================*
+ * Implementation
+ *==========================================================================*/
+
+static
+void
+nci_core_cancel_command(
+ NciCoreObject* self)
+{
+ if (self->cmd_id) {
+ gpointer user_data = self->rsp_data;
+
+ nci_sar_cancel(self->io.sar, self->cmd_id);
+ self->cmd_id = 0;
+ self->rsp_data = NULL;
+ if (self->cmd_timeout_id) {
+ g_source_remove(self->cmd_timeout_id);
+ self->cmd_timeout_id = 0;
+ }
+ if (self->rsp_handler) {
+ NciSmResponseFunc handler = self->rsp_handler;
+ GUtilData payload;
+
+ self->rsp_handler = NULL;
+ memset(&payload, 0, sizeof(payload));
+ handler(NCI_REQUEST_CANCELLED, &payload, user_data);
+ }
+ }
+}
+
+static
+void
+nci_core_command_completion(
+ NciSarClient* sar_client,
+ gboolean success,
+ gpointer user_data)
+{
+ if (!success) {
+ NciCoreObject* self = NCI_CORE(user_data);
+
+ GWARN("Failed to send command %02x/%02x", self->rsp_gid, self->rsp_oid);
+ nci_sm_stall(self->sm, NCI_STALL_ERROR);
+ }
+}
+
+static
+void
+nci_core_io_dummy_resp(
+ NCI_REQUEST_STATUS status,
+ const GUtilData* payload,
+ gpointer user_data)
+{
+ if (status != NCI_REQUEST_SUCCESS) {
+ GWARN("Command %02x/%02x failed", NCI_CORE(user_data)->rsp_gid,
+ NCI_CORE(user_data)->rsp_oid);
+ }
+}
+
+static
+gboolean
+nci_core_command_timeout(
+ gpointer user_data)
+{
+ NciCoreObject* self = NCI_CORE(user_data);
+ gpointer rsp_data = self->rsp_data;
+
+ GWARN("Command %02x/%02x timed out", self->rsp_gid, self->rsp_oid);
+ self->cmd_timeout_id = 0;
+ self->rsp_data = NULL;
+ nci_sar_cancel(self->io.sar, self->cmd_id);
+ self->cmd_id = 0;
+ if (self->rsp_handler) {
+ NciSmResponseFunc handler = self->rsp_handler;
+ GUtilData payload;
+
+ self->rsp_handler = NULL;
+ memset(&payload, 0, sizeof(payload));
+ handler(NCI_REQUEST_TIMEOUT, &payload, rsp_data);
+ }
+ nci_sm_stall(self->sm, NCI_STALL_ERROR);
+ return G_SOURCE_REMOVE;
+}
+
+static
+void
+nci_core_send_data_msg_complete(
+ NciSarClient* client,
+ gboolean ok,
+ gpointer user_data)
+{
+ NciCoreSendData* send = user_data;
+ NciCoreObject* self = nci_core_object_from_sar_client(client);
+
+ if (send->complete) {
+ send->complete(&self->core, ok, send->user_data);
+ }
+}
+
+static
+void
+nci_core_send_data_msg_destroy(
+ gpointer data)
+{
+ NciCoreSendData* send = data;
+
+ if (send->destroy) {
+ send->destroy(send->user_data);
+ }
+ g_slice_free(NciCoreSendData, send);
+}
+
+static
+void
+nci_core_last_state_changed(
+ NciSm* sm,
+ void* user_data)
+{
+ NciCoreObject* self = NCI_CORE(user_data);
+
+ self->core.current_state = sm->last_state->state;
+ g_signal_emit(self, nci_core_signals[SIGNAL_CURRENT_STATE], 0);
+}
+
+static
+void
+nci_core_next_state_changed(
+ NciSm* sm,
+ void* user_data)
+{
+ NciCoreObject* self = NCI_CORE(user_data);
+
+ self->core.next_state = sm->next_state->state;
+ g_signal_emit(self, nci_core_signals[SIGNAL_NEXT_STATE], 0);
+}
+
+static
+void
+nci_core_intf_activated(
+ NciSm* sm,
+ const NciIntfActivationNtf* ntf,
+ void* user_data)
+{
+ g_signal_emit(NCI_CORE(user_data), nci_core_signals
+ [SIGNAL_INTF_ACTIVATED], 0, ntf);
+}
+
+/*
+ * We can't directly connect the provided callback because
+ * it expects the first parameter to point to NciCore part
+ * of NciCoreObject but glib will invoke it with NciSmObject
+ * pointer as the first parameter. We need to replace the source.
+ */
+
+static
+void
+nci_core_closure_cb(
+ NciCoreObject* self,
+ NciCoreClosure* closure)
+{
+ closure->func(&self->core, closure->user_data);
+}
+
+static
+void
+nci_core_intf_activated_closure_cb(
+ NciCoreObject* self,
+ const NciIntfActivationNtf* ntf,
+ NciCoreIntfActivationClosure* closure)
+{
+ closure->func(&self->core, ntf, closure->user_data);
+}
+
+static
+void
+nci_core_data_packet_closure_cb(
+ NciCoreObject* self,
+ guint8 cid,
+ const void* payload,
+ guint len,
+ NciCoreDataPacketClosure* closure)
+{
+#pragma message("Use GUtilData for payload?")
+ closure->func(&self->core, cid, payload, len, closure->user_data);
+}
+
+static
+gulong
+nci_core_add_signal_handler(
+ NciCore* core,
+ NCI_CORE_SIGNAL signal,
+ NciCoreFunc func,
+ void* user_data)
+{
+ NciCoreObject* self = nci_core_object(core);
+
+ if (G_LIKELY(self) && G_LIKELY(func)) {
+ NciCoreClosure* closure = (NciCoreClosure*)
+ g_closure_new_simple(sizeof(NciCoreClosure), NULL);
+
+ closure->cclosure.closure.data = closure;
+ closure->cclosure.callback = G_CALLBACK(nci_core_closure_cb);
+ closure->func = func;
+ closure->user_data = user_data;
+
+ return g_signal_connect_closure_by_id(self, nci_core_signals[signal],
+ 0, &closure->cclosure.closure, FALSE);
+ }
+ return 0;
+}
+
+/*==========================================================================*
+ * NciSmIo callbacks
+ *==========================================================================*/
+
+static
+void
+nci_core_io_cancel(
+ NciSmIo* io)
+{
+ NciCoreObject* self = nci_core_object_from_sm_io(io);
+
+ self->rsp_handler = NULL;
+ self->rsp_data = NULL;
+ nci_core_cancel_command(self);
+}
+
+static
+gboolean
+nci_core_io_send(
+ NciSmIo* io,
+ guint8 gid,
+ guint8 oid,
+ GBytes* payload,
+ NciSmResponseFunc resp,
+ gpointer user_data)
+{
+ NciCoreObject* self = nci_core_object_from_sm_io(io);
+ NciCore* core = &self->core;
+
+ /* Cancel the previous one, if any */
+ nci_core_cancel_command(self);
+
+ self->rsp_gid = gid;
+ self->rsp_oid = oid;
+ if (resp) {
+ self->rsp_handler = resp;
+ self->rsp_data = user_data;
+ } else {
+ self->rsp_handler = nci_core_io_dummy_resp;
+ self->rsp_data = self;
+ }
+ self->cmd_id = nci_sar_send_command(self->io.sar, gid, oid, payload,
+ nci_core_command_completion, NULL, self);
+ if (self->cmd_id) {
+ if (core->cmd_timeout) {
+ self->cmd_timeout_id = g_timeout_add(core->cmd_timeout,
+ nci_core_command_timeout, self);
+ }
+ return TRUE;
+ } else {
+ self->rsp_handler = NULL;
+ self->rsp_data = NULL;
+ return FALSE;
+ }
+}
+
+/*==========================================================================*
+ * SAR client
+ *==========================================================================*/
+
+static
+void
+nci_core_sar_error(
+ NciSarClient* client)
+{
+ GWARN("State machine broke");
+ nci_sm_stall(nci_core_object_from_sar_client(client)->sm, NCI_STALL_ERROR);
+}
+
+static
+void
+nci_core_sar_handle_response(
+ NciSarClient* client,
+ guint8 gid,
+ guint8 oid,
+ const void* data,
+ guint len)
+{
+ NciCoreObject* self = nci_core_object_from_sar_client(client);
+
+ if (self->rsp_handler) {
+ if (self->rsp_gid == gid && self->rsp_oid == oid) {
+ NciSmResponseFunc handler = self->rsp_handler;
+ gpointer handler_data = self->rsp_data;
+ GUtilData payload;
+
+ if (self->cmd_timeout_id) {
+ g_source_remove(self->cmd_timeout_id);
+ self->cmd_timeout_id = 0;
+ }
+
+ self->cmd_id = 0;
+ self->rsp_handler = NULL;
+ self->rsp_data = NULL;
+
+ payload.bytes = data;
+ payload.size = len;
+ handler(NCI_REQUEST_SUCCESS, &payload, handler_data);
+ } else {
+ GWARN("Invalid response %02x/%02x", gid, oid);
+ }
+ } else {
+ GWARN("Unexpected response %02x/%02x", gid, oid);
+ }
+}
+
+static
+void
+nci_core_sar_handle_notification(
+ NciSarClient* client,
+ guint8 gid,
+ guint8 oid,
+ const void* payload_bytes,
+ guint payload_len)
+{
+ NciCoreObject* self = nci_core_object_from_sar_client(client);
+ GUtilData payload;
+
+ payload.bytes = payload_bytes;
+ payload.size = payload_len;
+ nci_sm_handle_ntf(self->sm, gid, oid, &payload);
+}
+
+static
+void
+nci_core_sar_handle_data_packet(
+ NciSarClient* client,
+ guint8 cid,
+ const void* payload,
+ guint len)
+{
+ g_signal_emit(nci_core_object_from_sar_client(client), nci_core_signals
+ [SIGNAL_DATA_PACKET], 0, cid, payload, len);
+}
+
+/*==========================================================================*
+ * Interface
+ *==========================================================================*/
+
+NciCore*
+nci_core_new(
+ NciHalIo* hal)
+{
+ if (G_LIKELY(hal)) {
+ NciCoreObject* self = g_object_new(NCI_TYPE_CORE, NULL);
+ NciCore* core = &self->core;
+ NciSm* sm;
+
+ self->io.sar = nci_sar_new(hal, &self->sar_client);
+ self->sm = sm = nci_sm_new(&self->io);
+
+ core->current_state = sm->last_state->state;
+ core->next_state = sm->next_state->state;
+
+ self->event_ids[EVENT_LAST_STATE] = nci_sm_add_last_state_handler(sm,
+ nci_core_last_state_changed, self);
+ self->event_ids[EVENT_NEXT_STATE] = nci_sm_add_next_state_handler(sm,
+ nci_core_next_state_changed, self);
+ self->event_ids[EVENT_INTF_ACTIVATED] =
+ nci_sm_add_intf_activated_handler(sm,
+ nci_core_intf_activated, self);
+ return core;
+ }
+ return NULL;
+}
+
+void
+nci_core_free(
+ NciCore* core)
+{
+ NciCoreObject* self = nci_core_object(core);
+
+ if (G_LIKELY(self)) {
+ NciSm* sm = self->sm;
+
+ sm->io = NULL;
+ nci_sar_free(self->io.sar);
+ self->io.sar = NULL;
+ g_object_unref(self);
+ }
+}
+
+void
+nci_core_restart(
+ NciCore* core)
+{
+ NciCoreObject* self = nci_core_object(core);
+
+ if (G_LIKELY(self)) {
+ nci_core_cancel_command(self);
+ nci_sar_reset(self->io.sar);
+ nci_sm_enter_state(self->sm, NCI_STATE_INIT, NULL);
+ nci_sm_switch_to(self->sm, NCI_RFST_IDLE);
+ }
+}
+
+void
+nci_core_set_state(
+ NciCore* core,
+ NCI_STATE state)
+{
+ NciCoreObject* self = nci_core_object(core);
+
+ if (G_LIKELY(self)) {
+ nci_sm_switch_to(self->sm, state);
+ }
+}
+
+guint
+nci_core_send_data_msg(
+ NciCore* core,
+ guint8 cid,
+ GBytes* payload,
+ NciCoreSendFunc complete,
+ GDestroyNotify destroy,
+ void* user_data)
+{
+ NciCoreObject* self = nci_core_object(core);
+
+ if (G_LIKELY(self)) {
+ if (complete || destroy) {
+ NciCoreSendData* data = g_slice_new0(NciCoreSendData);
+
+ data->complete = complete;
+ data->destroy = destroy;
+ data->user_data = user_data;
+ return nci_sar_send_data_packet(self->io.sar, cid, payload,
+ nci_core_send_data_msg_complete,
+ nci_core_send_data_msg_destroy, data);
+ } else {
+ return nci_sar_send_data_packet(self->io.sar, cid, payload,
+ NULL, NULL, NULL);
+ }
+ }
+ return 0;
+}
+
+void
+nci_core_cancel(
+ NciCore* core,
+ guint id)
+{
+ NciCoreObject* self = nci_core_object(core);
+
+ if (G_LIKELY(self)) {
+ nci_sar_cancel(self->io.sar, id);
+ }
+}
+
+gulong
+nci_core_add_current_state_changed_handler(
+ NciCore* core,
+ NciCoreFunc func,
+ void* data)
+{
+ return nci_core_add_signal_handler(core, SIGNAL_CURRENT_STATE, func, data);
+}
+
+gulong
+nci_core_add_next_state_changed_handler(
+ NciCore* core,
+ NciCoreFunc func,
+ void* data)
+{
+ return nci_core_add_signal_handler(core, SIGNAL_NEXT_STATE, func, data);
+}
+
+gulong
+nci_core_add_intf_activated_handler(
+ NciCore* core,
+ NciCoreIntfActivationFunc func,
+ void* user_data)
+{
+ NciCoreObject* self = nci_core_object(core);
+
+ if (G_LIKELY(self) && G_LIKELY(func)) {
+ NciCoreIntfActivationClosure* closure = (NciCoreIntfActivationClosure*)
+ g_closure_new_simple(sizeof(NciCoreIntfActivationClosure), NULL);
+ GCClosure* cclosure = &closure->cclosure;
+
+ cclosure->closure.data = closure;
+ cclosure->callback = G_CALLBACK(nci_core_intf_activated_closure_cb);
+ closure->func = func;
+ closure->user_data = user_data;
+
+ return g_signal_connect_closure_by_id(self, nci_core_signals
+ [SIGNAL_INTF_ACTIVATED], 0, &cclosure->closure, FALSE);
+ }
+ return 0;
+}
+
+gulong
+nci_core_add_data_packet_handler(
+ NciCore* core,
+ NciCoreDataPacketFunc func,
+ void* user_data)
+{
+ NciCoreObject* self = nci_core_object(core);
+
+ if (G_LIKELY(self) && G_LIKELY(func)) {
+ NciCoreDataPacketClosure* closure = (NciCoreDataPacketClosure*)
+ g_closure_new_simple(sizeof(NciCoreDataPacketClosure), NULL);
+ GCClosure* cclosure = &closure->cclosure;
+
+ cclosure->closure.data = closure;
+ cclosure->callback = G_CALLBACK(nci_core_data_packet_closure_cb);
+ closure->func = func;
+ closure->user_data = user_data;
+
+ return g_signal_connect_closure_by_id(self, nci_core_signals
+ [SIGNAL_DATA_PACKET], 0, &cclosure->closure, FALSE);
+ }
+ return 0;
+}
+
+void
+nci_core_remove_handler(
+ NciCore* core,
+ gulong id)
+{
+ NciCoreObject* self = nci_core_object(core);
+
+ if (G_LIKELY(self) && G_LIKELY(id)) {
+ g_signal_handler_disconnect(self, id);
+ }
+}
+
+void
+nci_core_remove_handlers(
+ NciCore* core,
+ gulong* ids,
+ guint count)
+{
+ gutil_disconnect_handlers(nci_core_object(core), ids, count);
+}
+
+/*==========================================================================*
+ * Internals
+ *==========================================================================*/
+
+static
+void
+nci_core_object_init(
+ NciCoreObject* self)
+{
+ static const NciSarClientFunctions sar_client_functions = {
+ .error = nci_core_sar_error,
+ .handle_response = nci_core_sar_handle_response,
+ .handle_notification = nci_core_sar_handle_notification,
+ .handle_data_packet = nci_core_sar_handle_data_packet
+ };
+
+ NciCore* core = &self->core;
+
+ core->cmd_timeout = DEFAULT_TIMEOUT;
+ self->sar_client.fn = &sar_client_functions;
+ self->io.send = nci_core_io_send;
+ self->io.cancel = nci_core_io_cancel;
+}
+
+static
+void
+nci_core_object_finalize(
+ GObject* object)
+{
+ NciCoreObject* self = NCI_CORE(object);
+
+ if (self->cmd_timeout_id) {
+ g_source_remove(self->cmd_timeout_id);
+ }
+ nci_sm_remove_all_handlers(self->sm, self->event_ids);
+ nci_sm_free(self->sm);
+ nci_sar_free(self->io.sar);
+ G_OBJECT_CLASS(nci_core_object_parent_class)->finalize(object);
+}
+
+static
+void
+nci_core_object_class_init(
+ NciCoreObjectClass* klass)
+{
+ G_OBJECT_CLASS(klass)->finalize = nci_core_object_finalize;
+ nci_core_signals[SIGNAL_CURRENT_STATE] =
+ g_signal_new(SIGNAL_CURRENT_STATE_NAME, G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
+ nci_core_signals[SIGNAL_NEXT_STATE] =
+ g_signal_new(SIGNAL_NEXT_STATE_NAME, G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
+ nci_core_signals[SIGNAL_INTF_ACTIVATED] =
+ g_signal_new(SIGNAL_INTF_ACTIVATED_NAME, G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1,
+ G_TYPE_POINTER);
+ nci_core_signals[SIGNAL_DATA_PACKET] =
+ g_signal_new(SIGNAL_DATA_PACKET_NAME, G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 3,
+ G_TYPE_UCHAR, G_TYPE_POINTER, G_TYPE_UINT);
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_log.h
^
|
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2018-2019 Jolla Ltd.
+ * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NCI_LOG_H
+#define NCI_LOG_H
+
+#include <nci_types.h>
+
+#define GLOG_MODULE_NAME NCI_LOG_MODULE
+#include <gutil_log.h>
+
+#endif /* NCI_LOG_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_param.c
^
|
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "nci_param_impl.h"
+
+G_DEFINE_ABSTRACT_TYPE(NciParam, nci_param, G_TYPE_OBJECT)
+
+/*==========================================================================*
+ * Interface
+ *==========================================================================*/
+
+NciParam*
+nci_param_ref(
+ NciParam* self)
+{
+ if (G_LIKELY(self)) {
+ g_object_ref(NCI_PARAM(self));
+ }
+ return self;
+}
+
+void
+nci_param_unref(
+ NciParam* self)
+{
+ if (G_LIKELY(self)) {
+ g_object_unref(NCI_PARAM(self));
+ }
+}
+
+/*==========================================================================*
+ * Internals
+ *==========================================================================*/
+
+static
+void
+nci_param_init(
+ NciParam* self)
+{
+}
+
+static
+void
+nci_param_class_init(
+ NciParamClass* klass)
+{
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_param.h
^
|
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NCI_PARAM_H
+#define NCI_PARAM_H
+
+#include "nci_types_p.h"
+
+#include <glib-object.h>
+
+struct nci_param {
+ GObject object;
+};
+
+GType nci_param_get_type(void);
+#define NCI_TYPE_PARAM nci_param_get_type()
+#define NCI_IS_PARAM(obj) G_TYPE_CHECK_INSTANCE_TYPE((obj), NCI_TYPE_PARAM)
+#define NCI_PARAM(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), NCI_TYPE_PARAM, \
+ NciParam)
+
+NciParam*
+nci_param_ref(
+ NciParam* param);
+
+void
+nci_param_unref(
+ NciParam* param);
+
+#endif /* NCI_PARAM_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_param_impl.h
^
|
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NCI_PARAM_IMPL_H
+#define NCI_PARAM_IMPL_H
+
+#include "nci_param.h"
+
+typedef struct nci_param_class {
+ GObjectClass parent;
+} NciParamClass;
+
+#endif /* NCI_PARAM_IMPL_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_param_w4_all_discoveries.c
^
|
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "nci_param_w4_all_discoveries.h"
+#include "nci_param_impl.h"
+#include "nci_util.h"
+
+typedef NciParamClass NciParamW4AllDiscoveriesClass;
+G_DEFINE_TYPE(NciParamW4AllDiscoveries, nci_param_w4_all_discoveries,
+ NCI_TYPE_PARAM)
+
+/*==========================================================================*
+ * Interface
+ *==========================================================================*/
+
+NciParamW4AllDiscoveries*
+nci_param_w4_all_discoveries_new(
+ const NciDiscoveryNtf* ntf)
+{
+ if (ntf) {
+ NciParamW4AllDiscoveries* self =
+ g_object_new(NCI_TYPE_PARAM_W4_ALL_DISCOVERIES, NULL);
+
+ self->ntf = nci_discovery_ntf_copy(ntf);
+ return self;
+ }
+ return NULL;
+}
+
+/*==========================================================================*
+ * Internals
+ *==========================================================================*/
+
+static
+void
+nci_param_w4_all_discoveries_init(
+ NciParamW4AllDiscoveries* self)
+{
+}
+
+static
+void
+nci_param_w4_all_discoveries_finalize(
+ GObject* obj)
+{
+ NciParamW4AllDiscoveries* self = NCI_PARAM_W4_ALL_DISCOVERIES(obj);
+
+ g_free(self->ntf);
+ G_OBJECT_CLASS(nci_param_w4_all_discoveries_parent_class)->finalize(obj);
+}
+
+static
+void
+nci_param_w4_all_discoveries_class_init(
+ NciParamClass* klass)
+{
+ G_OBJECT_CLASS(klass)->finalize = nci_param_w4_all_discoveries_finalize;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_param_w4_all_discoveries.h
^
|
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NCI_PARAM_W4_ALL_DISCOVERIES_H
+#define NCI_PARAM_W4_ALL_DISCOVERIES_H
+
+#include "nci_param.h"
+
+typedef struct nci_param_w4_all_discoveries {
+ NciParam param;
+ NciDiscoveryNtf* ntf;
+} NciParamW4AllDiscoveries;
+
+GType nci_param_w4_all_discoveries_get_type(void);
+#define NCI_TYPE_PARAM_W4_ALL_DISCOVERIES \
+ nci_param_w4_all_discoveries_get_type()
+#define NCI_IS_PARAM_W4_ALL_DISCOVERIES(obj) G_TYPE_CHECK_INSTANCE_TYPE((obj),\
+ NCI_TYPE_PARAM_W4_ALL_DISCOVERIES)
+#define NCI_PARAM_W4_ALL_DISCOVERIES(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ NCI_TYPE_PARAM_W4_ALL_DISCOVERIES, NciParamW4AllDiscoveries)
+
+NciParamW4AllDiscoveries*
+nci_param_w4_all_discoveries_new(
+ const NciDiscoveryNtf* ntf);
+
+#endif /* NCI_PARAM_W4_ALL_DISCOVERIES_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_param_w4_host_select.c
^
|
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "nci_param_w4_host_select.h"
+#include "nci_param_impl.h"
+#include "nci_util.h"
+
+typedef NciParamClass NciParamW4HostSelectClass;
+G_DEFINE_TYPE(NciParamW4HostSelect, nci_param_w4_host_select, NCI_TYPE_PARAM)
+
+/*==========================================================================*
+ * Interface
+ *==========================================================================*/
+
+NciParamW4HostSelect*
+nci_param_w4_host_select_new(
+ const NciDiscoveryNtf* const* ntf,
+ guint count)
+{
+ NciParamW4HostSelect* self =
+ g_object_new(NCI_TYPE_PARAM_W4_HOST_SELECT, NULL);
+
+ self->ntf = nci_discovery_ntf_copy_array(ntf, count);
+ self->count = count;
+ return self;
+}
+
+/*==========================================================================*
+ * Internals
+ *==========================================================================*/
+
+static
+void
+nci_param_w4_host_select_init(
+ NciParamW4HostSelect* self)
+{
+}
+
+static
+void
+nci_param_w4_host_select_finalize(
+ GObject* obj)
+{
+ NciParamW4HostSelect* self = NCI_PARAM_W4_HOST_SELECT(obj);
+
+ g_free(self->ntf);
+ G_OBJECT_CLASS(nci_param_w4_host_select_parent_class)->finalize(obj);
+}
+
+static
+void
+nci_param_w4_host_select_class_init(
+ NciParamClass* klass)
+{
+ G_OBJECT_CLASS(klass)->finalize = nci_param_w4_host_select_finalize;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_param_w4_host_select.h
^
|
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NCI_PARAM_W4_HOST_SELECT_H
+#define NCI_PARAM_W4_HOST_SELECT_H
+
+#include "nci_param.h"
+
+typedef struct nci_param_w4_host_select {
+ NciParam param;
+ NciDiscoveryNtf* ntf;
+ guint count;
+} NciParamW4HostSelect;
+
+GType nci_param_w4_host_select_get_type(void);
+#define NCI_TYPE_PARAM_W4_HOST_SELECT \
+ nci_param_w4_host_select_get_type()
+#define NCI_IS_PARAM_W4_HOST_SELECT(obj) G_TYPE_CHECK_INSTANCE_TYPE((obj),\
+ NCI_TYPE_PARAM_W4_HOST_SELECT)
+#define NCI_PARAM_W4_HOST_SELECT(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ NCI_TYPE_PARAM_W4_HOST_SELECT, NciParamW4HostSelect)
+
+NciParamW4HostSelect*
+nci_param_w4_host_select_new(
+ const NciDiscoveryNtf* const* ntfs,
+ guint count);
+
+#endif /* NCI_PARAM_W4_HOST_SELECT_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_sar.c
^
|
@@ -0,0 +1,905 @@
+/*
+ * Copyright (C) 2018-2019 Jolla Ltd.
+ * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "nci_sar.h"
+#include "nci_hal.h"
+#include "nci_log.h"
+
+#include <gutil_macros.h>
+
+/* SAR (Segmentation and Reassembly) */
+
+#define SAR_DEFAULT_MAX_LOGICAL_CONNECTIONS (1)
+#define SAR_DEFAULT_CONTROL_MTU (0x20)
+#define SAR_DEFAULT_DATA_MTU (0xff)
+#define SAR_MIN_MTU (0x04)
+#define SAR_UNLIMITED_CREDITS (0xff)
+
+#define NCI_HDR_SIZE (3)
+
+typedef struct nci_sar_packet_out NciSarPacketOut;
+
+struct nci_sar_packet_out {
+ NciSarPacketOut* next;
+ guint8 hdr[NCI_HDR_SIZE];
+ GBytes* payload;
+ guint payload_pos;
+ NciSarCompletionFunc complete;
+ GDestroyNotify destroy;
+ gpointer user_data;
+ guint id;
+};
+
+typedef struct nci_sar_packet_out_queue {
+ NciSarPacketOut* first;
+ NciSarPacketOut* last;
+} NciSarPacketOutQueue;
+
+typedef struct nci_sar_logical_connection {
+ guint8 credits;
+ GByteArray* in;
+ NciSarPacketOutQueue out;
+} NciSarLogicalConnection;
+
+struct nci_sar {
+ NciHalIo* io;
+ NciSarClient* client;
+ NciHalClient hal_client;
+ gboolean started;
+ guint8 max_logical_conns;
+ guint8 control_mtu;
+ guint8 data_mtu;
+ guint last_packet_id;
+ guint start_write_id;
+ gboolean write_pending;
+ NciSarPacketOut* writing;
+ NciSarPacketOutQueue cmd;
+ NciSarLogicalConnection* conn;
+ GByteArray* control_in;
+ GByteArray* read_buf;
+};
+
+/* Control packets */
+
+#define NCI_CONTROL_GID_MASK (0x0f) /* First octet */
+#define NCI_CONTROL_OID_MASK (0x3f) /* Second octet */
+
+/* Data packets */
+#define NCI_DATA_CID_MASK (0x0f)
+
+static
+void
+nci_sar_schedule_write(
+ NciSar* self);
+
+static
+void
+nci_sar_attempt_write(
+ NciSar* self);
+
+static
+NciSar*
+nci_sar_from_hal_client(
+ NciHalClient* hal_client)
+{
+ return G_CAST(hal_client, NciSar, hal_client);
+}
+
+static
+void
+nci_sar_packet_out_free(
+ NciSarPacketOut* out)
+{
+ /* Caller makes sure that argument is not NULL */
+ if (out->payload) {
+ g_bytes_unref(out->payload);
+ }
+ if (out->destroy) {
+ out->destroy(out->user_data);
+ }
+ g_slice_free(NciSarPacketOut, out);
+}
+
+static
+void
+nci_sar_write_completed(
+ NciHalClient* client,
+ gboolean ok)
+{
+ NciSar* self = nci_sar_from_hal_client(client);
+ NciSarPacketOut* out = self->writing;
+
+ GASSERT(out);
+ GASSERT(self->write_pending);
+ self->write_pending = FALSE;
+ if (ok) {
+ gsize payload_len = out->payload ? g_bytes_get_size(out->payload) : 0;
+
+ GASSERT(payload_len >= out->payload_pos);
+ if (payload_len == out->payload_pos) {
+ /* Done with this packet */
+ self->writing = NULL;
+ if (out->complete) {
+ out->complete(self->client, TRUE, out->user_data);
+ }
+ nci_sar_packet_out_free(out);
+ }
+
+ /* And try to write the next segment or packet */
+ nci_sar_attempt_write(self);
+ } else {
+ NciSarClient* client = self->client;
+
+ /* Drop this packet and indicate an error */
+ self->writing = NULL;
+ if (out->complete) {
+ out->complete(self->client, FALSE, out->user_data);
+ }
+ nci_sar_packet_out_free(out);
+ client->fn->error(client);
+ }
+}
+
+static
+NciSarPacketOutQueue*
+nci_sar_write_queue(
+ NciSar* self,
+ gboolean eat_credit)
+{
+ if (self->cmd.first) {
+ return &self->cmd;
+ } else {
+ guint i;
+
+ for (i = 0; i < self->max_logical_conns; i++) {
+ NciSarLogicalConnection* conn = self->conn + i;
+
+ if (conn->out.first && conn->credits) {
+ if (eat_credit) {
+ conn->credits--;
+ }
+ return &conn->out;
+ }
+ }
+ }
+ return NULL;
+}
+
+static
+gboolean
+nci_sar_can_write(
+ NciSar* self)
+{
+ return !self->writing && nci_sar_write_queue(self, FALSE);
+}
+
+static
+void
+nci_sar_attempt_write(
+ NciSar* self)
+{
+ if (!self->write_pending) {
+ if (!self->writing) {
+ NciSarPacketOutQueue* queue = nci_sar_write_queue(self, TRUE);
+
+ if (queue) {
+ self->writing = queue->first;
+ queue->first = self->writing->next;
+ self->writing->next = NULL;
+ if (!queue->first) {
+ queue->last = NULL;
+ }
+ }
+ }
+ if (self->writing) {
+ NciHalIo* io = self->io;
+ NciSarPacketOut* out = self->writing;
+ guint total_len = NCI_HDR_SIZE; /* +1 for payload length */
+ const guint8* payload = NULL;
+ gsize remaining_payload_len = 0;
+ GUtilData chunks[2];
+ int nchunks = 1;
+ gboolean write_submitted = FALSE;
+ const guint mtu = ((out->hdr[0] & NCI_MT_MASK) ==
+ NCI_MT_CMD_PKT) ? self->control_mtu : self->data_mtu;
+
+ if (out->payload) {
+ gsize payload_len = 0;
+
+ payload = g_bytes_get_data(out->payload, &payload_len);
+ GASSERT(payload_len >= out->payload_pos);
+ remaining_payload_len = payload_len - out->payload_pos;
+ total_len += remaining_payload_len;
+ }
+
+ chunks[0].bytes = out->hdr;
+ chunks[0].size = NCI_HDR_SIZE;
+ if (total_len <= mtu) {
+ /* We can send the whole thing */
+ out->hdr[0] &= ~NCI_PBF;
+ out->hdr[2] = (guint8)remaining_payload_len;
+ if (remaining_payload_len) {
+ chunks[nchunks].bytes = payload + out->payload_pos;
+ chunks[nchunks].size = remaining_payload_len;
+ out->payload_pos += remaining_payload_len;
+ nchunks++;
+ }
+ } else {
+ /* Send a fragment */
+ out->hdr[0] |= NCI_PBF;
+ out->hdr[2] = mtu;
+ chunks[nchunks].bytes = payload;
+ chunks[nchunks].size = mtu - chunks[0].size;
+ out->payload_pos += chunks[nchunks].size;
+ nchunks++;
+ }
+
+ /* Start HAL on demand */
+ if (!self->started) {
+ self->started = io->fn->start(io, &self->hal_client);
+ }
+
+ /* Submit write request to the HAL */
+ if (self->started) {
+ self->write_pending = TRUE;
+ if (io->fn->write(io, chunks, nchunks,
+ nci_sar_write_completed)) {
+ write_submitted = TRUE;
+ } else {
+ self->write_pending = FALSE;
+ }
+ }
+
+ /* Bail out if something went wrong */
+ if (!write_submitted) {
+ NciSarClient* client = self->client;
+
+ /* Drop this packet and indicate an error */
+ self->writing = NULL;
+ if (out->complete) {
+ out->complete(self->client, FALSE, out->user_data);
+ }
+ nci_sar_packet_out_free(out);
+ client->fn->error(client);
+
+ /* Try the next one even though it will probably fail too */
+ nci_sar_schedule_write(self);
+ }
+ }
+ }
+}
+
+static
+gboolean
+nci_sar_start_write(
+ gpointer user_data)
+{
+ NciSar* self = user_data;
+
+ self->start_write_id = 0;
+ nci_sar_attempt_write(self);
+ return G_SOURCE_REMOVE;
+}
+
+static
+void
+nci_sar_schedule_write(
+ NciSar* self)
+{
+ if (!self->start_write_id && nci_sar_can_write(self)) {
+ self->start_write_id = g_idle_add(nci_sar_start_write, self);
+ }
+}
+
+static
+guint
+nci_sar_send(
+ NciSar* self,
+ NciSarPacketOutQueue* queue,
+ const guint8* hdr,
+ GBytes* payload,
+ NciSarCompletionFunc complete,
+ GDestroyNotify destroy,
+ gpointer user_data)
+{
+ guint id = 0;
+ NciSarPacketOut* out = g_slice_new0(NciSarPacketOut);
+
+ /* Generate id */
+ id = (++self->last_packet_id);
+ if (!id) id = (++self->last_packet_id);
+
+ /* Fill in the packet structure */
+ out->id = id;
+ out->complete = complete;
+ out->destroy = destroy;
+ out->user_data = user_data;
+ memcpy(out->hdr, hdr, NCI_HDR_SIZE - 1); /* Ignore the length */
+ if (payload) {
+ out->payload = g_bytes_ref(payload);
+ }
+
+ /* Queue the packet */
+ if (queue->last) {
+ GASSERT(queue->first);
+ queue->last->next = out;
+ queue->last = out;
+ } else {
+ GASSERT(!queue->first);
+ queue->first = queue->last = out;
+ }
+
+ /* Schedule write */
+ nci_sar_schedule_write(self);
+ return id;
+}
+
+static
+void
+nci_sar_hal_handle_control_packet(
+ NciSar* self,
+ guint8 mt,
+ guint8 gid,
+ guint8 oid,
+ const guint8* payload,
+ guint payload_len)
+{
+ NciSarClient* client = self->client;
+
+ if (mt == NCI_MT_RSP_PKT) {
+ client->fn->handle_response(client, gid, oid, payload, payload_len);
+ } else {
+ GASSERT(mt == NCI_MT_NTF_PKT);
+ client->fn->handle_notification(client, gid, oid, payload, payload_len);
+ }
+}
+
+static
+void
+nci_sar_hal_handle_data_packet(
+ NciSar* self,
+ guint cid,
+ const guint8* payload,
+ guint payload_len)
+{
+ NciSarClient* client = self->client;
+
+ client->fn->handle_data_packet(client, cid, payload, payload_len);
+}
+
+static
+void
+nci_sar_hal_handle_control_segment(
+ NciSar* self,
+ const guint8* packet,
+ guint len)
+{
+ const guint8 hdr = packet[0];
+ const guint8 mt = (hdr & NCI_MT_MASK);
+ const guint8 gid = (hdr & NCI_CONTROL_GID_MASK);
+ const guint8 oid = (packet[1] & NCI_CONTROL_OID_MASK);
+ const guint8 payload_len = packet[2];
+ const guint8* payload = packet + NCI_HDR_SIZE;
+ NciSarClient* client = self->client;
+ GByteArray* in = self->control_in;
+
+ /* For each segment of a Control Message, the header of the
+ * Control Packet SHALL contain the same MT, GID and OID values. */
+ if (in && in->len > 0) {
+ if (mt == (in->data[0] & NCI_MT_MASK) &&
+ gid == (in->data[0] & NCI_CONTROL_GID_MASK) &&
+ oid == (in->data[1] & NCI_CONTROL_OID_MASK)) {
+ /* Only append the payload */
+ g_byte_array_append(in, payload, payload_len);
+ if (!(hdr & NCI_PBF)) {
+ /* This was the last segment. Since we are about to
+ * invoke external code, zero self->control_in to
+ * make sure that data doesn't get modified. */
+ self->control_in = NULL;
+ nci_sar_hal_handle_control_packet(self, mt, gid, oid,
+ in->data + NCI_HDR_SIZE, in->len - NCI_HDR_SIZE);
+ g_byte_array_set_size(in, 0);
+ if (!self->control_in) {
+ /* Restore the pointer */
+ self->control_in = in;
+ } else {
+ g_byte_array_free(in, TRUE);
+ }
+ }
+ } else {
+ GDEBUG("MT/GID/OID mismatch for segmented control packet");
+ client->fn->error(client);
+ }
+ } else if (hdr & NCI_PBF) {
+ /* First segment of a segmented packet */
+ if (!in) {
+ in = self->control_in = g_byte_array_new();
+ }
+ g_byte_array_append(in, packet, payload_len + NCI_HDR_SIZE);
+ } else {
+ /* Complete packet */
+ nci_sar_hal_handle_control_packet(self, mt, gid, oid, payload,
+ payload_len);
+ }
+}
+
+static
+void
+nci_sar_hal_handle_data_segment(
+ NciSar* self,
+ const guint8* packet,
+ guint len)
+{
+ const guint8 hdr = packet[0];
+ const guint8 cid = (hdr & NCI_DATA_CID_MASK);
+ const guint8 payload_len = packet[2];
+ const guint8* payload = packet + NCI_HDR_SIZE;
+ NciSarClient* client = self->client;
+
+ if (cid < self->max_logical_conns) {
+ NciSarLogicalConnection* conn = self->conn + cid;
+ GByteArray* in = conn->in;
+
+ if (in && in->len > 0) {
+ /* Only append the payload */
+ g_byte_array_append(in, payload, payload_len);
+ if (!(hdr & NCI_PBF)) {
+ /* This was the last segment. Since we are about to
+ * invoke external code, zero data_in[cid] to ensure
+ * that data doesn't get modified. */
+ conn->in = NULL;
+ nci_sar_hal_handle_data_packet(self, cid,
+ in->data + NCI_HDR_SIZE, in->len - NCI_HDR_SIZE);
+ g_byte_array_set_size(in, 0);
+ if (!conn->in) {
+ /* Restore the pointer */
+ conn->in = in;
+ } else {
+ g_byte_array_free(in, TRUE);
+ }
+ }
+ } else if (hdr & NCI_PBF) {
+ /* First segment of a segmented packet */
+ if (!in) {
+ in = conn->in = g_byte_array_new();
+ }
+ g_byte_array_append(in, packet, payload_len + NCI_HDR_SIZE);
+ } else {
+ /* Complete packet */
+ nci_sar_hal_handle_data_packet(self, cid, payload, payload_len);
+ }
+ } else {
+ GDEBUG("Invalid logical connection 0x%02x", cid);
+ client->fn->error(client);
+ }
+}
+
+static
+void
+nci_sar_hal_handle_segment(
+ NciSar* self,
+ const guint8* packet,
+ guint len)
+{
+ const guint8 mt = packet[0] & NCI_MT_MASK;
+ NciSarClient* client = self->client;
+
+ switch (mt) {
+ case NCI_MT_DATA_PKT:
+ nci_sar_hal_handle_data_segment(self, packet, len);
+ break;
+ case NCI_MT_RSP_PKT:
+ case NCI_MT_NTF_PKT:
+ nci_sar_hal_handle_control_segment(self, packet, len);
+ break;
+ case NCI_MT_CMD_PKT:
+ /* We are not supposed to receive a command from NFCC */
+ default:
+ GDEBUG("Unsupported message type 0x%02x", mt);
+ client->fn->error(client);
+ break;
+ }
+}
+
+/*==========================================================================*
+ * HAL client
+ *==========================================================================*/
+
+static
+void
+nci_sar_hal_client_error(
+ NciHalClient* hal_client)
+{
+ NciSar* self = nci_sar_from_hal_client(hal_client);
+ NciSarClient* client = self->client;
+
+ /* Forward it to our client */
+ client->fn->error(client);
+}
+
+static
+void
+nci_sar_hal_client_read(
+ NciHalClient* hal_client,
+ const void* data,
+ guint len)
+{
+ NciSar* self = nci_sar_from_hal_client(hal_client);
+ const guint8* bytes = data;
+
+ if (!self->read_buf || !self->read_buf->len) {
+ /* Optimal (and usual) case - full packets are coming in */
+ while (len > 2 && len >= (bytes[2] + NCI_HDR_SIZE)) {
+ const guint packet_len = bytes[2] + NCI_HDR_SIZE;
+
+ nci_sar_hal_handle_segment(self, bytes, packet_len);
+ bytes += packet_len;
+ len -= packet_len;
+ }
+ }
+
+ if (len > 0) {
+ GByteArray* buf = self->read_buf;
+
+ if (!buf) {
+ buf = self->read_buf = g_byte_array_new();
+ }
+
+ /* This is something non-trivial (partial or fragmented packet) */
+ g_byte_array_append(buf, bytes, len);
+ while (buf->len > 2 && buf->len >= (buf->data[2] + NCI_HDR_SIZE)) {
+ const guint packet_len = buf->data[2] + NCI_HDR_SIZE;
+
+ nci_sar_hal_handle_segment(self, buf->data, packet_len);
+ g_byte_array_remove_range(buf, 0, packet_len);
+ }
+ }
+}
+
+static
+void
+nci_sar_clear_queue(
+ NciSarPacketOutQueue* queue)
+{
+ while (queue->first) {
+ NciSarPacketOut* out = queue->first;
+
+ queue->first = out->next;
+ nci_sar_packet_out_free(out);
+ }
+ queue->last = NULL;
+}
+
+static
+gboolean
+nci_sar_cancel_queue(
+ NciSar* self,
+ NciSarPacketOutQueue* queue,
+ guint id)
+{
+ if (queue->first) {
+ NciSarPacketOut* out = queue->first;
+
+ if (out->id == id) {
+ if (!(queue->first = out->next)) {
+ queue->last = NULL;
+ }
+ nci_sar_packet_out_free(out);
+ return TRUE;
+ } else {
+ NciSarPacketOut* prev = out;
+
+ out = out->next;
+ while (out) {
+ if (out->id == id) {
+ prev->next = out->next;
+ if (!prev->next) {
+ queue->last = prev;
+ }
+ nci_sar_packet_out_free(out);
+ return TRUE;
+ }
+ prev = out;
+ out = out->next;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/*==========================================================================*
+ * Interface
+ *==========================================================================*/
+
+NciSar*
+nci_sar_new(
+ NciHalIo* io,
+ NciSarClient* client)
+{
+ NciSar* self = g_slice_new0(NciSar);
+ static const NciHalClientFunctions hal_functions = {
+ .error = nci_sar_hal_client_error,
+ .read = nci_sar_hal_client_read
+ };
+
+ self->hal_client.fn = &hal_functions;
+ self->client = client;
+ self->io = io;
+ self->max_logical_conns = SAR_DEFAULT_MAX_LOGICAL_CONNECTIONS;
+ self->control_mtu = SAR_DEFAULT_CONTROL_MTU;
+ self->data_mtu = SAR_DEFAULT_DATA_MTU;
+ self->conn = g_new0(NciSarLogicalConnection, self->max_logical_conns);
+ return self;
+}
+
+void
+nci_sar_free(
+ NciSar* self)
+{
+ if (G_LIKELY(self)) {
+ guint i;
+
+ nci_sar_reset(self);
+
+ /* Free things that nci_sar_reset() didn't deallocate */
+ for (i = 0; i < self->max_logical_conns; i++) {
+ NciSarLogicalConnection* conn = self->conn + i;
+
+ if (conn->in) {
+ g_byte_array_free(conn->in, TRUE);
+ }
+ }
+ if (self->control_in) {
+ g_byte_array_free(self->control_in, TRUE);
+ }
+ if (self->read_buf) {
+ g_byte_array_free(self->read_buf, TRUE);
+ }
+ g_free(self->conn);
+ g_slice_free(NciSar, self);
+ }
+}
+
+gboolean
+nci_sar_start(
+ NciSar* self)
+{
+ if (G_LIKELY(self)) {
+ NciHalIo* io = self->io;
+
+ if (!self->started) {
+ self->started = io->fn->start(io, &self->hal_client);
+ }
+ return self->started;
+ }
+ return FALSE;
+}
+
+void
+nci_sar_reset(
+ NciSar* self)
+{
+ if (G_LIKELY(self)) {
+ guint i;
+
+ if (self->started) {
+ NciHalIo* io = self->io;
+
+ self->started = FALSE;
+ io->fn->stop(io);
+ }
+
+ for (i = 0; i < self->max_logical_conns; i++) {
+ NciSarLogicalConnection* conn = self->conn + i;
+
+ nci_sar_clear_queue(&conn->out);
+ conn->credits = 0;
+ if (conn->in) {
+ g_byte_array_set_size(conn->in, 0);
+ }
+ }
+
+ if (self->control_in) {
+ g_byte_array_set_size(self->control_in, 0);
+ }
+
+ if (self->writing) {
+ /* Stop canceled it already */
+ nci_sar_packet_out_free(self->writing);
+ self->writing = NULL;
+ }
+
+ nci_sar_clear_queue(&self->cmd);
+ if (self->start_write_id) {
+ g_source_remove(self->start_write_id);
+ self->start_write_id = 0;
+ }
+ }
+}
+
+void
+nci_sar_set_max_logical_connections(
+ NciSar* self,
+ guint8 max)
+{
+ if (G_LIKELY(self)) {
+ guint i;
+
+ if (!max) {
+ max = SAR_DEFAULT_MAX_LOGICAL_CONNECTIONS;
+ }
+ if (max > self->max_logical_conns) {
+ self->conn = g_realloc(self->conn, sizeof(self->conn[0]) * max);
+ memset(self->conn + self->max_logical_conns, 0,
+ sizeof(self->conn[0]) * (max - self->max_logical_conns));
+ self->max_logical_conns = max;
+ } else if (max < self->max_logical_conns) {
+ for (i = max; i < self->max_logical_conns; i++) {
+ NciSarLogicalConnection* conn = self->conn + i;
+
+ nci_sar_clear_queue(&conn->out);
+ if (conn->in) {
+ g_byte_array_free(conn->in, TRUE);
+ }
+ }
+ self->conn = g_realloc(self->conn, sizeof(self->conn[0]) * max);
+ self->max_logical_conns = max;
+ }
+ }
+}
+
+void
+nci_sar_set_max_control_packet_size(
+ NciSar* self,
+ guint8 max)
+{
+ if (G_LIKELY(self)) {
+ if (max < SAR_MIN_MTU) {
+ self->control_mtu = max ? SAR_MIN_MTU : SAR_DEFAULT_CONTROL_MTU;
+ } else {
+ self->control_mtu = max;
+ }
+ }
+}
+
+void
+nci_sar_set_initial_credits(
+ NciSar* self,
+ guint8 cid,
+ guint8 credits)
+{
+ if (G_LIKELY(self) && cid < self->max_logical_conns) {
+ /* The queue should be empty at this point */
+ GASSERT(!self->conn[cid].out.first);
+ self->conn[cid].credits = credits;
+ }
+}
+
+void
+nci_sar_add_credits(
+ NciSar* self,
+ guint8 cid,
+ guint8 credits)
+{
+ if (G_LIKELY(self) && cid < self->max_logical_conns) {
+ NciSarLogicalConnection* conn = self->conn + cid;
+
+ if (credits > (0xff - conn->credits)) {
+ GWARN("Credits overflow");
+ conn->credits = SAR_UNLIMITED_CREDITS;
+ } else {
+ conn->credits += credits;
+ }
+ if (conn->out.first) {
+ nci_sar_schedule_write(self);
+ }
+ }
+}
+
+guint
+nci_sar_send_command(
+ NciSar* self,
+ guint8 gid,
+ guint8 oid,
+ GBytes* payload,
+ NciSarCompletionFunc complete,
+ GDestroyNotify destroy,
+ gpointer user_data)
+{
+ GASSERT(!(gid & ~NCI_CONTROL_GID_MASK));
+ GASSERT(!(oid & ~NCI_CONTROL_OID_MASK));
+ if (G_LIKELY(self)) {
+ guint8 hdr[NCI_HDR_SIZE];
+
+ hdr[0] = NCI_MT_CMD_PKT | (gid & NCI_CONTROL_GID_MASK);
+ hdr[1] = oid & NCI_CONTROL_OID_MASK;
+ return nci_sar_send(self, &self->cmd, hdr, payload, complete,
+ destroy, user_data);
+ }
+ return 0;
+}
+
+guint
+nci_sar_send_data_packet(
+ NciSar* self,
+ guint8 cid,
+ GBytes* payload,
+ NciSarCompletionFunc complete,
+ GDestroyNotify destroy,
+ gpointer user_data)
+{
+ GASSERT(!(cid & ~NCI_DATA_CID_MASK));
+ if (G_LIKELY(self) && cid < self->max_logical_conns) {
+ NciSarLogicalConnection* conn = self->conn + cid;
+ guint8 hdr[NCI_HDR_SIZE];
+
+ hdr[0] = cid & NCI_DATA_CID_MASK;
+ hdr[1] = 0;
+ return nci_sar_send(self, &conn->out, hdr, payload, complete,
+ destroy, user_data);
+ }
+ return 0;
+}
+
+void
+nci_sar_cancel(
+ NciSar* self,
+ guint id)
+{
+ if (G_LIKELY(self) && G_LIKELY(id)) {
+ if (self->writing && self->writing->id == id) {
+ /* We can't really cancel the packet once we started writing it.
+ * Just clear the completion callback. */
+ self->writing->complete = NULL;
+ return;
+ } else if (!nci_sar_cancel_queue(self, &self->cmd, id)) {
+ guint i;
+
+ for (i = 0; i < self->max_logical_conns; i++) {
+ NciSarLogicalConnection* conn = self->conn + i;
+
+ if (nci_sar_cancel_queue(self, &conn->out, id)) {
+ return;
+ }
+ }
+ }
+ GWARN("Invalid packet id %u", id);
+ }
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_sar.h
^
|
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2018-2019 Jolla Ltd.
+ * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NCI_SAR_H
+#define NCI_SAR_H
+
+#include "nci_types_p.h"
+
+/* SAR (Segmentation and Reassembly) */
+
+typedef struct nci_sar_client NciSarClient;
+
+typedef struct nci_sar_client_functions {
+ void (*error)(NciSarClient* client);
+ void (*handle_response)(NciSarClient* client, guint8 gid, guint8 oid,
+ const void* payload, guint payload_len);
+ void (*handle_notification)(NciSarClient* client, guint8 gid, guint8 oid,
+ const void* payload, guint payload_len);
+ void (*handle_data_packet)(NciSarClient* client, guint8 cid,
+ const void* payload, guint payload_len);
+} NciSarClientFunctions;
+
+struct nci_sar_client {
+ const NciSarClientFunctions* fn;
+};
+
+typedef
+void
+(*NciSarCompletionFunc)(
+ NciSarClient* client,
+ gboolean success,
+ gpointer user_data);
+
+NciSar*
+nci_sar_new(
+ NciHalIo* io,
+ NciSarClient* client);
+
+void
+nci_sar_free(
+ NciSar* sar);
+
+gboolean
+nci_sar_start(
+ NciSar* sar);
+
+void
+nci_sar_reset(
+ NciSar* sar);
+
+void
+nci_sar_set_max_logical_connections(
+ NciSar* sar,
+ guint8 max);
+
+void
+nci_sar_set_max_control_packet_size(
+ NciSar* sar,
+ guint8 max);
+
+void
+nci_sar_set_initial_credits(
+ NciSar* sar,
+ guint8 cid,
+ guint8 credits);
+
+void
+nci_sar_add_credits(
+ NciSar* sar,
+ guint8 cid,
+ guint8 credits);
+
+guint
+nci_sar_send_command(
+ NciSar* sar,
+ guint8 gid,
+ guint8 oid,
+ GBytes* payload,
+ NciSarCompletionFunc complete,
+ GDestroyNotify destroy,
+ gpointer user_data);
+
+guint
+nci_sar_send_data_packet(
+ NciSar* sar,
+ guint8 cid,
+ GBytes* payload,
+ NciSarCompletionFunc complete,
+ GDestroyNotify destroy,
+ gpointer user_data);
+
+void
+nci_sar_cancel(
+ NciSar* sar,
+ guint id);
+
+#endif /* NFC_SAR_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_sm.c
^
|
@@ -0,0 +1,985 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "nci_sm.h"
+#include "nci_sar.h"
+#include "nci_param.h"
+#include "nci_state_p.h"
+#include "nci_transition.h"
+#include "nci_log.h"
+
+#include <gutil_idlepool.h>
+#include <gutil_macros.h>
+#include <gutil_misc.h>
+
+#include <glib-object.h>
+
+typedef GObjectClass NciSmObjectClass;
+
+typedef struct nci_sm_closure {
+ GCClosure cclosure;
+ NciSmFunc func;
+ gpointer* user_data;
+} NciSmClosure;
+
+typedef struct nci_sm_intf_activated_closure {
+ GCClosure cclosure;
+ NciSmIntfActivationFunc func;
+ gpointer* user_data;
+} NciSmIntfActivationClosure;
+
+typedef struct nci_sm_object {
+ GObject object;
+ NciSm sm;
+ GUtilIdlePool* pool;
+ GPtrArray* states;
+ GPtrArray* transitions;
+ NciTransition* reset_transition;
+ NciTransition* next_transition;
+ NciTransition* active_transition;
+ NciState* active_state;
+ guint32 pending_signals;
+} NciSmObject;
+
+G_DEFINE_TYPE(NciSmObject, nci_sm_object, G_TYPE_OBJECT)
+#define NCI_TYPE_SM (nci_sm_object_get_type())
+#define NCI_SM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ NCI_TYPE_SM, NciSmObject))
+#define NCI_SM_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), \
+ NCI_TYPE_SM, NciSmObjectClass)
+
+typedef enum nci_sm_signal {
+ SIGNAL_NEXT_STATE,
+ SIGNAL_LAST_STATE,
+ SIGNAL_INTF_ACTIVATED,
+ SIGNAL_COUNT
+} NCI_SM_SIGNAL;
+
+#define SIGNAL_LAST_STATE_NAME "nci-sm-last-state"
+#define SIGNAL_NEXT_STATE_NAME "nci-sm-next-state"
+#define SIGNAL_INTF_ACTIVATED_NAME "nci-sm-intf-activated"
+
+static guint nci_sm_signals[SIGNAL_COUNT] = { 0 };
+
+#define NCI_IS_INTERNAL_STATE(state) ((state) < NCI_RFST_IDLE)
+
+static inline NciSmObject* nci_sm_object(NciSm* sm) /* NULL safe */
+ { return G_LIKELY(sm) ? NCI_SM(G_CAST(sm, NciSmObject, sm)) : NULL; }
+
+/*==========================================================================*
+ * Implementation
+ *==========================================================================*/
+
+static
+inline
+void
+nci_sm_queue_signal(
+ NciSmObject* self,
+ NCI_SM_SIGNAL sig)
+{
+ self->pending_signals |= (1 << sig);
+}
+
+static
+void
+nci_sm_emit_pending_signals(
+ NciSmObject* self)
+{
+ if (self->pending_signals) {
+ GObject* obj = &self->object;
+ int sig;
+
+ /* Handlers could drops their references to us */
+ g_object_ref(obj);
+ for (sig = 0; self->pending_signals && sig < SIGNAL_COUNT; sig++) {
+ const guint32 signal_bit = (1 << sig);
+ if (self->pending_signals & signal_bit) {
+ self->pending_signals &= ~signal_bit;
+ g_signal_emit(obj, nci_sm_signals[sig], 0);
+ }
+ }
+ /* And release the temporary reference */
+ g_object_unref(obj);
+ }
+}
+
+static
+NciState*
+nci_sm_add_new_state(
+ NciSm* sm,
+ NciState* (*fn)(NciSm* sm))
+{
+ NciState* state = fn(sm);
+
+ nci_sm_add_state(sm, state);
+ nci_state_unref(state);
+ return state;
+}
+
+static
+void
+nci_sm_add_new_transition(
+ NciSm* sm,
+ NCI_STATE state,
+ NciTransition* (*fn)(NciSm* sm))
+{
+ NciTransition* transition = fn(sm);
+
+ nci_sm_add_transition(sm, state, transition);
+ nci_transition_unref(transition);
+}
+
+static
+void
+nci_sm_weak_pointer_notify(
+ gpointer data,
+ GObject* dead_object)
+{
+ NciSm** ptr = data;
+ NciSmObject* dead_self = G_CAST(dead_object, NciSmObject, object);
+
+ if (*ptr == &dead_self->sm) {
+ *ptr = NULL;
+ }
+}
+
+static
+void
+nci_sm_finish_active_transition(
+ NciSmObject* self)
+{
+ if (self->active_transition) {
+ NciTransition* finished = self->active_transition;
+
+ self->active_transition = NULL;
+ nci_transition_finished(finished);
+ nci_transition_unref(finished);
+ }
+}
+
+static
+gboolean
+nci_sm_start_transition(
+ NciSmObject* self,
+ NciTransition* transition)
+{
+ /* Caller checks that transition is not NULL */
+ if (self->active_transition != transition) {
+ nci_sm_finish_active_transition(self);
+ }
+
+ /* Optimistically mark this transition as active */
+ self->active_transition = nci_transition_ref(transition);
+ if (nci_transition_start(transition)) {
+ /* Transition has started, deactivate the state */
+ if (self->active_state) {
+ nci_state_leave(self->active_state);
+ self->active_state = NULL;
+ }
+ return TRUE;
+ } else if (self->active_transition == transition) {
+ /* Ne need to finish it because it hasn't beenstarted */
+ nci_transition_unref(self->active_transition);
+ self->active_transition = NULL;
+ }
+ return FALSE;
+}
+
+static
+void
+nci_sm_set_last_state(
+ NciSmObject* self,
+ NciState* state)
+{
+ NciSm* sm = &self->sm;
+
+ if (sm->last_state != state && state) {
+ GDEBUG("Current state %s -> %s", sm->last_state->name, state->name);
+ sm->last_state = state;
+ nci_sm_queue_signal(self, SIGNAL_LAST_STATE);
+ }
+}
+
+static
+void
+nci_sm_set_next_state(
+ NciSmObject* self,
+ NciState* state)
+{
+ NciSm* sm = &self->sm;
+
+ if (sm->next_state != state && state) {
+ GDEBUG("Next state %s -> %s", sm->next_state->name, state->name);
+ sm->next_state = state;
+ nci_sm_queue_signal(self, SIGNAL_NEXT_STATE);
+ }
+}
+
+static
+NciState*
+nci_sm_state_by_id(
+ NciSmObject* self,
+ NCI_STATE id)
+{
+ const GPtrArray* states = self->states;
+ const guint index = (guint)id;
+
+ if (index < states->len) {
+ gpointer state = states->pdata[index];
+
+ if (state) {
+ return NCI_STATE(state);
+ }
+ }
+ GWARN("Unknown state %d", id);
+ return NULL;
+}
+
+static
+void
+nci_sm_stall_internal(
+ NciSmObject* self,
+ NCI_STALL type)
+{
+ NciSmIo* io = self->sm.io;
+ NciState* state = nci_sm_state_by_id(self, (type == NCI_STALL_STOP) ?
+ NCI_STATE_STOP : NCI_STATE_ERROR);
+
+ if (G_LIKELY(io)) {
+ io->cancel(io);
+ }
+ nci_sm_finish_active_transition(self);
+ nci_sm_set_last_state(self, state);
+ nci_sm_set_next_state(self, state);
+ if (self->active_state != state) {
+ if (self->active_state) {
+ nci_state_leave(self->active_state);
+ }
+ self->active_state = state;
+ nci_state_enter(state, NULL);
+ }
+ nci_sm_emit_pending_signals(self);
+}
+
+static
+void
+nci_sm_enter_state_internal(
+ NciSmObject* self,
+ NciState* state,
+ NciParam* param)
+{
+ NciTransition* next_transition;
+
+ /* Entering any state terminates the transition */
+ nci_sm_finish_active_transition(self);
+
+ /* Activate the new state */
+ if (state == self->active_state) {
+ nci_state_reenter(state, param);
+ } else {
+ if (self->active_state) {
+ nci_state_leave(self->active_state);
+ }
+ self->active_state = state;
+ nci_state_enter(state, param);
+ }
+
+ /* Start the next transition if there is any */
+ next_transition = self->next_transition;
+ self->next_transition = NULL;
+ if (next_transition && next_transition->dest == state) {
+ nci_transition_unref(next_transition);
+ next_transition = NULL;
+ }
+
+ if (next_transition) {
+ nci_sm_start_transition(self, next_transition);
+ nci_transition_unref(next_transition);
+ }
+
+ nci_sm_set_last_state(self, state);
+ if (!self->active_transition) {
+ nci_sm_set_next_state(self, state);
+ }
+ nci_sm_emit_pending_signals(self);
+}
+
+/*
+ * We can't directly connect the provided callback because it expects
+ * the first parameter to point to NciSm part of NciSmObject but glib
+ * will invoke it with NciSmObject pointer as the first parameter. We
+ * need to replace the source.
+ */
+
+static
+void
+nci_sm_closure_cb(
+ NciSmObject* self,
+ NciSmClosure* closure)
+{
+ closure->func(&self->sm, closure->user_data);
+}
+
+static
+void
+nci_sm_intf_activated_closure_cb(
+ NciSmObject* self,
+ const NciIntfActivationNtf* ntf,
+ NciSmIntfActivationClosure* closure)
+{
+ closure->func(&self->sm, ntf, closure->user_data);
+}
+
+static
+gulong
+nci_sm_add_signal_handler(
+ NciSm* sm,
+ NCI_SM_SIGNAL signal,
+ NciSmFunc func,
+ void* user_data)
+{
+ NciSmObject* self = nci_sm_object(sm);
+
+ if (G_LIKELY(self) && G_LIKELY(func)) {
+ NciSmClosure* closure = (NciSmClosure*)
+ g_closure_new_simple(sizeof(NciSmClosure), NULL);
+
+ closure->cclosure.closure.data = closure;
+ closure->cclosure.callback = G_CALLBACK(nci_sm_closure_cb);
+ closure->func = func;
+ closure->user_data = user_data;
+
+ return g_signal_connect_closure_by_id(self, nci_sm_signals[signal], 0,
+ &closure->cclosure.closure, FALSE);
+ }
+ return 0;
+}
+
+/*==========================================================================*
+ * Interface
+ *==========================================================================*/
+
+NciState*
+nci_sm_enter_state(
+ NciSm* sm,
+ NCI_STATE id,
+ NciParam* param)
+{
+ NciSmObject* self = nci_sm_object(sm);
+
+ if (G_LIKELY(self)) {
+ const GPtrArray* states = self->states;
+ const guint index = (guint)id;
+
+ if (index < states->len) {
+ gpointer state_ptr = states->pdata[index];
+
+ if (state_ptr) {
+ NciState* state = NCI_STATE(state_ptr);
+
+ nci_param_ref(param);
+ nci_sm_enter_state_internal(self, state, param);
+ nci_param_unref(param);
+ return state;
+ }
+ }
+ GERR("Unknown state %d", id);
+ }
+ return NULL;
+}
+
+void
+nci_sm_switch_to(
+ NciSm* sm,
+ NCI_STATE id)
+{
+ NciState* next = nci_sm_get_state(sm, id);
+
+ if (G_LIKELY(next) && sm->next_state != next) {
+ NciSmObject* self = nci_sm_object(sm);
+
+ if (self->next_transition) {
+ nci_transition_unref(self->next_transition);
+ self->next_transition = NULL;
+ }
+ if (self->active_transition) {
+ NciState* dest = self->active_transition->dest;
+
+ if (dest != next) {
+ self->next_transition = nci_state_get_transition(dest, id);
+ if (self->next_transition) {
+ nci_transition_ref(self->next_transition);
+ nci_sm_set_next_state(self, next);
+ } else if (NCI_IS_INTERNAL_STATE(id)) {
+ /* Internal states are entered without transition
+ * and take no parameters */
+ nci_sm_enter_state_internal(self, next, NULL);
+ } else {
+ GERR("No transition %s -> %s", dest->name, next->name);
+ nci_sm_stall_internal(self, NCI_STALL_ERROR);
+ }
+ }
+ } else {
+ NciTransition* next_transition =
+ nci_state_get_transition(sm->last_state, id);
+
+ if (next_transition) {
+ if (nci_sm_start_transition(self, next_transition)) {
+ nci_sm_set_next_state(self, next);
+ } else {
+ nci_sm_stall_internal(self, NCI_STALL_ERROR);
+ }
+ } else if (NCI_IS_INTERNAL_STATE(id)) {
+ /* Internal states are entered without transition and
+ * take no parameters. */
+ nci_sm_enter_state_internal(self, next, NULL);
+ } else {
+ NciState* idle = nci_sm_state_by_id(self, NCI_RFST_IDLE);
+
+ /* Switch to idle state first */
+ if (nci_sm_start_transition(self, self->reset_transition)) {
+ if (id == NCI_RFST_IDLE) {
+ nci_sm_set_next_state(self, idle);
+ } else {
+ self->next_transition =
+ nci_state_get_transition(idle, id);
+ if (self->next_transition) {
+ nci_transition_ref(self->next_transition);
+ nci_sm_set_next_state(self, next);
+ } else {
+ GERR("No transition %s -> %s", idle->name,
+ next->name);
+ nci_sm_stall_internal(self, NCI_STALL_ERROR);
+ }
+ }
+ } else {
+ nci_sm_stall_internal(self, NCI_STALL_ERROR);
+ }
+ }
+ }
+ nci_sm_emit_pending_signals(self);
+ }
+}
+
+void
+nci_sm_stall(
+ NciSm* sm,
+ NCI_STALL type)
+{
+ NciSmObject* self = nci_sm_object(sm);
+
+ if (G_LIKELY(self)) {
+ nci_sm_stall_internal(self, type);
+ }
+}
+
+/*==========================================================================*
+ * Interface for NciCore
+ *==========================================================================*/
+
+NciSm*
+nci_sm_new(
+ NciSmIo* io)
+{
+ NciSmObject* self = g_object_new(NCI_TYPE_SM, NULL);
+ NciSm* sm = &self->sm;
+ NciTransition* deactivate_to_idle;
+
+ sm->io = io;
+
+ /* Default setup */
+ nci_sm_add_new_state(sm, nci_state_idle_new);
+ nci_sm_add_new_state(sm, nci_state_discovery_new);
+ nci_sm_add_new_state(sm, nci_state_poll_active_new);
+ nci_sm_add_new_state(sm, nci_state_w4_all_discoveries_new);
+ nci_sm_add_new_state(sm, nci_state_w4_host_select_new);
+
+ /*
+ * Reset transition could be added to the internal states, i.e.
+ * NCI_STATE_INIT, NCI_STATE_ERROR and NCI_STATE_STOP but it's
+ * not really necessary. If the last state doesn't know where
+ * to go, reset transition is applied anyway and state machine
+ * then happily continues from NCI_RFST_IDLE state. So the end
+ * result would be the same as if we didn't add any transitions
+ * to the internal states.
+ */
+ self->reset_transition = nci_transition_reset_new(sm);
+
+ /* Set up the transitions */
+ deactivate_to_idle = nci_transition_deactivate_to_idle_new(sm);
+ nci_sm_add_transition(sm, NCI_RFST_DISCOVERY, deactivate_to_idle);
+ nci_sm_add_transition(sm, NCI_RFST_W4_ALL_DISCOVERIES, deactivate_to_idle);
+ nci_sm_add_transition(sm, NCI_RFST_W4_HOST_SELECT, deactivate_to_idle);
+ nci_transition_unref(deactivate_to_idle);
+
+ nci_sm_add_new_transition(sm,
+ NCI_RFST_IDLE, nci_transition_idle_to_discovery_new);
+ nci_sm_add_new_transition(sm,
+ NCI_RFST_POLL_ACTIVE, nci_transition_poll_active_to_discovery_new);
+ nci_sm_add_new_transition(sm,
+ NCI_RFST_POLL_ACTIVE, nci_transition_poll_active_to_idle_new);
+ return sm;
+}
+
+void
+nci_sm_free(
+ NciSm* sm)
+{
+ NciSmObject* self = nci_sm_object(sm);
+
+ if (G_LIKELY(self)) {
+ g_object_unref(self);
+ }
+}
+
+void
+nci_sm_handle_ntf(
+ NciSm* sm,
+ guint8 gid,
+ guint8 oid,
+ const GUtilData* data)
+{
+ NciSmObject* self = nci_sm_object(sm);
+
+ if (self) {
+ if (self->active_transition) {
+ nci_transition_handle_ntf(self->active_transition, gid, oid, data);
+ } else {
+ GASSERT(sm->last_state);
+ nci_state_handle_ntf(sm->last_state, gid, oid, data);
+ }
+ }
+}
+
+void
+nci_sm_add_state(
+ NciSm* sm,
+ NciState* state)
+{
+ NciSmObject* self = nci_sm_object(sm);
+
+ if (G_LIKELY(self) && G_LIKELY(state)) {
+ GPtrArray* states = self->states;
+
+ if (states->len <= state->state) {
+ g_ptr_array_set_size(states, state->state + 1);
+ }
+ if (states->pdata[state->state] != state) {
+ nci_state_unref(states->pdata[state->state]);
+ states->pdata[state->state] = nci_state_ref(state);
+ }
+ }
+}
+
+void
+nci_sm_add_transition(
+ NciSm* sm,
+ NCI_STATE state,
+ NciTransition* transition)
+{
+ NciSmObject* self = nci_sm_object(sm);
+
+ if (G_LIKELY(self) && G_LIKELY(transition)) {
+ NciState* src = nci_sm_state_by_id(self, state);
+
+ if (G_LIKELY(src)) {
+ g_ptr_array_add(self->transitions, nci_transition_ref(transition));
+ nci_state_add_transition(src, transition);
+ }
+ }
+}
+
+gulong
+nci_sm_add_last_state_handler(
+ NciSm* sm,
+ NciSmFunc func,
+ void* user_data)
+{
+ return nci_sm_add_signal_handler(sm, SIGNAL_LAST_STATE, func, user_data);
+}
+
+gulong
+nci_sm_add_next_state_handler(
+ NciSm* sm,
+ NciSmFunc func,
+ void* user_data)
+{
+ return nci_sm_add_signal_handler(sm, SIGNAL_NEXT_STATE, func, user_data);
+}
+
+gulong
+nci_sm_add_intf_activated_handler(
+ NciSm* sm,
+ NciSmIntfActivationFunc func,
+ void* user_data)
+{
+ NciSmObject* self = nci_sm_object(sm);
+
+ if (G_LIKELY(self) && G_LIKELY(func)) {
+ NciSmIntfActivationClosure* closure = (NciSmIntfActivationClosure*)
+ g_closure_new_simple(sizeof(NciSmIntfActivationClosure), NULL);
+ GCClosure* cclosure = &closure->cclosure;
+
+ cclosure->closure.data = closure;
+ cclosure->callback = G_CALLBACK(nci_sm_intf_activated_closure_cb);
+ closure->func = func;
+ closure->user_data = user_data;
+
+ return g_signal_connect_closure_by_id(self, nci_sm_signals
+ [SIGNAL_INTF_ACTIVATED], 0, &cclosure->closure, FALSE);
+ }
+ return 0;
+}
+
+void
+nci_sm_remove_handler(
+ NciSm* sm,
+ gulong id)
+{
+ if (G_LIKELY(id)) {
+ NciSmObject* self = nci_sm_object(sm);
+
+ if (G_LIKELY(self)) {
+ g_signal_handler_disconnect(self, id);
+ }
+ }
+}
+
+void
+nci_sm_remove_handlers(
+ NciSm* sm,
+ gulong* ids,
+ guint count)
+{
+ NciSmObject* self = nci_sm_object(sm);
+
+ if (G_LIKELY(self)) {
+ gutil_disconnect_handlers(self, ids, count);
+ }
+}
+
+/*==========================================================================*
+ * Interface for states and transitions
+ *==========================================================================*/
+
+NciSar*
+nci_sm_sar(
+ NciSm* sm)
+{
+ return (G_LIKELY(sm) && G_LIKELY(sm->io)) ? sm->io->sar : NULL;
+}
+
+void
+nci_sm_add_weak_pointer(
+ NciSm** ptr)
+{
+ if (G_LIKELY(ptr)) {
+ NciSmObject* self = nci_sm_object(*ptr);
+
+ if (self) {
+ g_object_weak_ref(&self->object, nci_sm_weak_pointer_notify, ptr);
+ }
+ }
+}
+
+void
+nci_sm_remove_weak_pointer(
+ NciSm** ptr)
+{
+ if (G_LIKELY(ptr)) {
+ NciSmObject* self = nci_sm_object(*ptr);
+
+ if (self) {
+ g_object_weak_unref(&self->object, nci_sm_weak_pointer_notify, ptr);
+ *ptr = NULL;
+ }
+ }
+}
+
+gboolean
+nci_sm_supports_protocol(
+ NciSm* sm,
+ NCI_PROTOCOL protocol)
+{
+ switch (protocol) {
+ case NCI_PROTOCOL_T2T:
+ case NCI_PROTOCOL_ISO_DEP:
+ return TRUE;
+ case NCI_PROTOCOL_UNDETERMINED:
+ case NCI_PROTOCOL_T1T:
+ case NCI_PROTOCOL_T3T:
+ case NCI_PROTOCOL_NFC_DEP:
+ break;
+ }
+ return FALSE;
+}
+
+gboolean
+nci_sm_active_transition(
+ NciSm* sm,
+ NciTransition* transition)
+{
+ NciSmObject* self = nci_sm_object(sm);
+
+ return G_LIKELY(self) && G_LIKELY(transition) &&
+ self->active_transition == transition;
+}
+
+NciState*
+nci_sm_get_state(
+ NciSm* sm,
+ NCI_STATE id)
+{
+ NciSmObject* self = nci_sm_object(sm);
+
+ return G_LIKELY(self) ? nci_sm_state_by_id(self, id) : NULL;
+}
+
+gboolean
+nci_sm_send_command(
+ NciSm* sm,
+ guint8 gid,
+ guint8 oid,
+ GBytes* payload,
+ NciSmResponseFunc resp,
+ gpointer user_data)
+{
+ if (G_LIKELY(sm)) {
+ NciSmIo* io = sm->io;
+
+ if (G_LIKELY(io)) {
+ return io->send(io, gid, oid, payload, resp, user_data);
+ }
+ }
+ return FALSE;
+}
+
+gboolean
+nci_sm_send_command_static(
+ NciSm* sm,
+ guint8 gid,
+ guint8 oid,
+ const void* payload,
+ gsize payload_len,
+ NciSmResponseFunc resp,
+ gpointer user_data)
+{
+ gboolean ok = FALSE;
+
+ if (G_LIKELY(sm)) {
+ NciSmIo* io = sm->io;
+
+ if (G_LIKELY(io)) {
+ GBytes* bytes = g_bytes_new_static(payload, payload_len);
+
+ ok = io->send(io, gid, oid, bytes, resp, user_data);
+ g_bytes_unref(bytes);
+ }
+ }
+ return ok;
+}
+
+void
+nci_sm_intf_activated(
+ NciSm* sm,
+ const NciIntfActivationNtf* ntf)
+{
+ NciSmObject* self = nci_sm_object(sm);
+
+ if (G_LIKELY(self)) {
+ nci_sar_set_initial_credits(nci_sm_sar(sm), NCI_STATIC_RF_CONN_ID,
+ ntf->num_credits);
+ g_signal_emit(self, nci_sm_signals[SIGNAL_INTF_ACTIVATED], 0, ntf);
+ }
+}
+
+/*==========================================================================*
+ * Notification handlers
+ *==========================================================================*/
+
+void
+nci_sm_handle_conn_credits_ntf(
+ NciSm* sm,
+ const GUtilData* payload)
+{
+ NciSar* sar = (sm && sm->io) ? sm->io->sar : NULL;
+
+ if (sar) {
+ /*
+ * Table 17: Control Messages for Connection Credit Management
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | Number of Entries (n) |
+ * | 1 | 2*n | Entries |
+ * | | +-----------------------------------------+
+ * | | | Size | Description |
+ * | | +-----------------------------------------+
+ * | | | 1 | Conn ID |
+ * | | | 1 | Credits |
+ * +=========================================================+
+ */
+ if (payload->size > 0) {
+ const guint n = payload->bytes[0];
+
+ if (payload->size >= (1 + 2 * n)) {
+ const guint8* entry = payload->bytes + 1;
+ guint i;
+
+ GDEBUG("CORE_CONN_CREDITS_NTF");
+ for (i = 0; i < n; i++, entry += 2) {
+ nci_sar_add_credits(sar, entry[0], entry[1]);
+ }
+ return;
+ }
+ }
+ GWARN("Failed to parse CORE_CONN_CREDITS_NTF");
+ nci_sm_stall(sm, NCI_STALL_ERROR);
+ }
+}
+
+void
+nci_sm_handle_rf_deactivate_ntf(
+ NciSm* sm,
+ const GUtilData* payload)
+{
+ NciSar* sar = (sm && sm->io) ? sm->io->sar : NULL;
+
+ if (sar) {
+ /*
+ * Table 62: Control Messages for RF Interface Deactivation
+ *
+ * RF_DEACTIVATE_NTF
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | Deactivation Type |
+ * | 1 | 1 | Deactivation Reason |
+ * +=========================================================+
+ */
+ if (payload->size >= 2) {
+ const guint8 type = payload->bytes[0];
+
+ switch (type) {
+ case NCI_DEACTIVATE_TYPE_IDLE:
+ GDEBUG("RF_DEACTIVATE_NTF Idle (%u)", payload->bytes[1]);
+ nci_sm_enter_state(sm, NCI_RFST_IDLE, NULL);
+ return;
+ case NCI_DEACTIVATE_TYPE_DISCOVERY:
+ GDEBUG("RF_DEACTIVATE_NTF Discovery (%u)", payload->bytes[1]);
+ nci_sm_enter_state(sm, NCI_RFST_DISCOVERY, NULL);
+ return;
+ default:
+ GDEBUG("RF_DEACTIVATE_NTF %u (%u)", type, payload->bytes[1]);
+ break;
+ }
+ }
+ GWARN("Failed to parse CORE_CONN_CREDITS_NTF");
+ nci_sm_stall(sm, NCI_STALL_ERROR);
+ }
+}
+
+/*==========================================================================*
+ * Internals
+ *==========================================================================*/
+
+static
+void
+nci_sm_object_init(
+ NciSmObject* self)
+{
+ NciSm* sm = &self->sm;
+
+ self->pool = gutil_idle_pool_new();
+ self->transitions = g_ptr_array_new_with_free_func((GDestroyNotify)
+ nci_transition_unref);
+ self->states = g_ptr_array_new_full(NCI_CORE_STATES, (GDestroyNotify)
+ nci_state_unref);
+
+ /* Internal states are always there */
+ self->active_state = sm->last_state = sm->next_state =
+ nci_sm_add_new_state(sm, nci_state_init_new);
+ nci_sm_add_new_state(sm, nci_state_error_new);
+ nci_sm_add_new_state(sm, nci_state_stop_new);
+
+ /* Enter the initial state */
+ nci_state_enter(self->active_state, NULL);
+}
+
+static
+void
+nci_sm_object_finalize(
+ GObject* object)
+{
+ NciSmObject* self = NCI_SM(object);
+ NciSm* sm = &self->sm;
+
+ nci_sm_finish_active_transition(self);
+ nci_state_leave(self->active_state);
+ if (sm->rf_interfaces) {
+ g_bytes_unref(sm->rf_interfaces);
+ }
+ nci_transition_unref(self->next_transition);
+ g_ptr_array_free(self->transitions, TRUE);
+ g_ptr_array_free(self->states, TRUE);
+ nci_transition_unref(self->reset_transition);
+ gutil_idle_pool_destroy(self->pool);
+ G_OBJECT_CLASS(nci_sm_object_parent_class)->finalize(object);
+}
+
+static
+void
+nci_sm_object_class_init(
+ NciSmObjectClass* klass)
+{
+ G_OBJECT_CLASS(klass)->finalize = nci_sm_object_finalize;
+ nci_sm_signals[SIGNAL_LAST_STATE] =
+ g_signal_new(SIGNAL_LAST_STATE_NAME, G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
+ nci_sm_signals[SIGNAL_NEXT_STATE] =
+ g_signal_new(SIGNAL_NEXT_STATE_NAME, G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
+ nci_sm_signals[SIGNAL_INTF_ACTIVATED] =
+ g_signal_new(SIGNAL_INTF_ACTIVATED_NAME, G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1,
+ G_TYPE_POINTER);
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_sm.h
^
|
@@ -0,0 +1,423 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NCI_STATE_MACHINE_H
+#define NCI_STATE_MACHINE_H
+
+#include "nci_types_p.h"
+
+/* RF Communication State Machine */
+
+typedef enum nci_interface_version {
+ NCI_INTERFACE_VERSION_UNKNOWN,
+ NCI_INTERFACE_VERSION_1,
+ NCI_INTERFACE_VERSION_2
+} NCI_INTERFACE_VERSION;
+
+/* Table 9: NFCC Features */
+typedef enum nci_nfcc_discovery {
+ NCI_NFCC_DISCOVERY_NONE = 0x00,
+ NCI_NFCC_DISCOVERY_FREQUENCY_CONFIG = 0x01,
+ NCI_NFCC_DISCOVERY_RF_CONFIG_MERGE = 0x02
+} NCI_NFCC_DISCOVERY;
+
+typedef enum nci_nfcc_routing {
+ NCI_NFCC_ROUTING_NONE = 0x00,
+ NCI_NFCC_ROUTING_TECHNOLOGY_BASED = 0x02,
+ NCI_NFCC_ROUTING_PROTOCOL_BASED = 0x04,
+ NCI_NFCC_ROUTING_AID_BASED = 0x08
+} NCI_NFCC_ROUTING;
+
+typedef enum nci_nfcc_power {
+ NCI_NFCC_POWER_NONE = 0x00,
+ NCI_NFCC_POWER_BATTERY_OFF = 0x01,
+ NCI_NFCC_POWER_SWITCH_OFF = 0x02
+} NCI_NFCC_POWER;
+
+/* Table 43: Value Field for Mode */
+#define NCI_DISCOVER_MAP_MODE_POLL (0x01)
+#define NCI_DISCOVER_MAP_MODE_LISTEN (0x02)
+
+/* Table 46: TLV Coding for Listen Mode Routing */
+#define NCI_ROUTING_ENTRY_TYPE_TECHNOLOGY (0x00)
+#define NCI_ROUTING_ENTRY_TYPE_PROTOCOL (0x01)
+#define NCI_ROUTING_ENTRY_TYPE_AID (0x02)
+
+/* Table 50: Value Field for Power State */
+#define NCI_ROUTING_ENTRY_POWER_ON (0x01)
+#define NCI_ROUTING_ENTRY_POWER_OFF (0x02)
+#define NCI_ROUTING_ENTRY_POWER_BATTERY_OFF (0x04)
+#define NCI_ROUTING_ENTRY_POWER_ALL (0x07)
+
+/* Table 63: Deactivation Types */
+typedef enum nci_deactivation_type {
+ NCI_DEACTIVATE_TYPE_IDLE = 0x00,
+ NCI_DEACTIVATE_TYPE_SLEEP = 0x01,
+ NCI_DEACTIVATE_TYPE_SLEEP_AF = 0x02,
+ NCI_DEACTIVATE_TYPE_DISCOVERY = 0x03
+} NCI_DEACTIVATION_TYPE;
+
+/* Table 64: Deactivation Reasons */
+typedef enum nci_deactivation_reason {
+ NCI_DEACTIVATION_REASON_DH_REQUEST = 0x00,
+ NCI_DEACTIVATION_REASON_ENDPOINT_REQUEST = 0x01,
+ NCI_DEACTIVATION_REASON_RF_LINK_LOSS = 0x02,
+ NCI_DEACTIVATION_REASON_BAD_AFI = 0x03
+} NCI_DEACTIVATION_REASON;
+
+/* Table 84: NFCEE IDs */
+#define NCI_NFCEE_ID_DH (0x00)
+
+/* Table 94: Status Codes */
+#define NCI_STATUS_OK (0x00)
+#define NCI_STATUS_REJECTED (0x01)
+#define NCI_STATUS_RF_FRAME_CORRUPTED (0x02)
+#define NCI_STATUS_FAILED (0x03)
+#define NCI_STATUS_NOT_INITIALIZED (0x04)
+#define NCI_STATUS_SYNTAX_ERROR (0x05)
+#define NCI_STATUS_SEMANTIC_ERROR (0x06)
+#define NCI_STATUS_INVALID_PARAM (0x09)
+#define NCI_STATUS_MESSAGE_SIZE_EXCEEDED (0x0a)
+#define NCI_DISCOVERY_ALREADY_STARTED (0xa0)
+#define NCI_DISCOVERY_TARGET_ACTIVATION_FAILED (0xa1)
+#define NCI_DISCOVERY_TEAR_DOWN (0xa2)
+#define NCI_RF_TRANSMISSION_ERROR (0xb0)
+#define NCI_RF_PROTOCOL_ERROR (0xb1)
+#define NCI_RF_TIMEOUT_ERROR (0xb2)
+#define NCI_NFCEE_INTERFACE_ACTIVATION_FAILED (0xc0)
+#define NCI_NFCEE_TRANSMISSION_ERROR (0xc1)
+#define NCI_NFCEE_PROTOCOL_ERROR (0xc2)
+#define NCI_NFCEE_TIMEOUT_ERROR (0xc3)
+
+/* Table 95: RF Technologies */
+typedef enum nci_rf_technology {
+ NCI_RF_TECHNOLOGY_A = 0x00,
+ NCI_RF_TECHNOLOGY_B = 0x01,
+ NCI_RF_TECHNOLOGY_F = 0x02,
+ NCI_RF_TECHNOLOGY_15693 = 0x03
+} NCI_RF_TECHNOLOGY;
+
+/* Table 101: Configuration Parameter Tags */
+
+/* Common Discovery Parameters */
+#define NCI_CONFIG_TOTAL_DURATION (0x00)
+#define NCI_CONFIG_CON_DEVICES_LIMIT (0x01)
+
+/* Poll Mode: NFC-A Discovery Parameters */
+#define NCI_CONFIG_PA_BAIL_OUT (0x08)
+
+/* Poll Mode: NFC-B Discovery Parameters */
+#define NCI_CONFIG_PB_AFI (0x10)
+#define NCI_CONFIG_PB_BAIL_OUT (0x11)
+#define NCI_CONFIG_PB_ATTRIB_PARAM1 (0x12)
+#define NCI_CONFIG_PB_SENSB_REQ_PARAM (0x13)
+
+/* Poll Mode: NFC-F Discovery Parameters */
+#define NCI_CONFIG_PF_BIT_RATE (0x18)
+#define NCI_CONFIG_PF_RC_CODE (0x19)
+
+/* Poll Mode: ISO-DEP Discovery Parameters */
+#define NCI_CONFIG_PB_H_INFO (0x20)
+#define NCI_CONFIG_PI_BIT_RATE (0x21)
+#define NCI_CONFIG_PA_ADV_FEAT (0x22)
+
+/* Poll Mode: NFC-DEP Discovery Parameters */
+#define NCI_CONFIG_PN_NFC_DEP_SPEED (0x28)
+#define NCI_CONFIG_PN_ATR_REQ_GEN_BYTES (0x29)
+#define NCI_CONFIG_PN_ATR_REQ_CONFIG (0x2A)
+
+/* Listen Mode: NFC-A Discovery Parameters */
+#define NCI_CONFIG_LA_BIT_FRAME_SDD (0x30)
+#define NCI_CONFIG_LA_PLATFORM_CONFIG (0x31)
+#define NCI_CONFIG_LA_SEL_INFO (0x32)
+#define NCI_CONFIG_LA_NFCID1 (0x33)
+
+/* Listen Mode: NFC-B Discovery Parameters */
+#define NCI_CONFIG_LB_SENSB_INFO (0x38)
+#define NCI_CONFIG_LB_NFCID0 (0x39)
+#define NCI_CONFIG_LB_APPLICATION_DATA (0x3A)
+#define NCI_CONFIG_LB_SFGI (0x3B)
+#define NCI_CONFIG_LB_ADC_FO (0x3C)
+
+/* Listen Mode: NFC-F Discovery Parameters */
+#define NCI_CONFIG_LF_T3T_IDENTIFIERS_1 (0x40)
+#define NCI_CONFIG_LF_T3T_IDENTIFIERS_2 (0x41)
+#define NCI_CONFIG_LF_T3T_IDENTIFIERS_3 (0x42)
+#define NCI_CONFIG_LF_T3T_IDENTIFIERS_4 (0x43)
+#define NCI_CONFIG_LF_T3T_IDENTIFIERS_5 (0x44)
+#define NCI_CONFIG_LF_T3T_IDENTIFIERS_6 (0x45)
+#define NCI_CONFIG_LF_T3T_IDENTIFIERS_7 (0x46)
+#define NCI_CONFIG_LF_T3T_IDENTIFIERS_8 (0x47)
+#define NCI_CONFIG_LF_T3T_IDENTIFIERS_9 (0x48)
+#define NCI_CONFIG_LF_T3T_IDENTIFIERS_10 (0x49)
+#define NCI_CONFIG_LF_T3T_IDENTIFIERS_11 (0x4A)
+#define NCI_CONFIG_LF_T3T_IDENTIFIERS_12 (0x4B)
+#define NCI_CONFIG_LF_T3T_IDENTIFIERS_13 (0x4C)
+#define NCI_CONFIG_LF_T3T_IDENTIFIERS_14 (0x4D)
+#define NCI_CONFIG_LF_T3T_IDENTIFIERS_15 (0x4E)
+#define NCI_CONFIG_LF_T3T_IDENTIFIERS_16 (0x4F)
+#define NCI_CONFIG_LF_PROTOCOL_TYPE (0x50)
+#define NCI_CONFIG_LF_T3T_PMM (0x51)
+#define NCI_CONFIG_LF_T3T_MAX (0x52)
+#define NCI_CONFIG_LF_T3T_FLAGS (0x53)
+#define NCI_CONFIG_LF_CON_BITR_F (0x54)
+#define NCI_CONFIG_LF_ADV_FEAT (0x55)
+
+/* Listen Mode: ISO-DEP Discovery Parameters */
+#define NCI_CONFIG_LI_FWI (0x58)
+#define NCI_CONFIG_LA_HIST_BY (0x59)
+#define NCI_CONFIG_LB_H_INFO_RESP (0x5A)
+#define NCI_CONFIG_LI_BIT_RATE (0x5B)
+
+/* Listen Mode: NFC-DEP Discovery Parameters */
+#define NCI_CONFIG_LN_WT (0x60)
+#define NCI_CONFIG_LN_ATR_RES_GEN_BYTES (0x61)
+#define NCI_CONFIG_LN_ATR_RES_CONFIG (0x62)
+#define NCI_CONFIG_RF_FIELD_INFO (0x80)
+#define NCI_CONFIG_RF_NFCEE_ACTION (0x81)
+#define NCI_CONFIG_NFCDEP_OP (0x82)
+
+/* Table 102: GID and OID Definitions */
+
+/* GID values */
+#define NCI_GID_CORE (0x00)
+#define NCI_GID_RF (0x01)
+#define NCI_GID_NFCEE (0x02)
+
+/* OID values */
+#define NCI_OID_CORE_RESET (0x00)
+#define NCI_OID_CORE_INIT (0x01)
+#define NCI_OID_CORE_SET_CONFIG (0x02)
+#define NCI_OID_CORE_GET_CONFIG (0x03)
+#define NCI_OID_CORE_CONN_CREATE (0x04)
+#define NCI_OID_CORE_CONN_CLOSE (0x05)
+#define NCI_OID_CORE_CONN_CREDITS (0x06)
+#define NCI_OID_CORE_GENERIC_ERROR (0x07)
+#define NCI_OID_CORE_INTERFACE_ERROR (0x08)
+
+#define NCI_OID_RF_DISCOVER_MAP (0x00)
+#define NCI_OID_RF_SET_LISTEN_MODE_ROUTING (0x01)
+#define NCI_OID_RF_GET_LISTEN_MODE_ROUTING (0x02)
+#define NCI_OID_RF_DISCOVER (0x03)
+#define NCI_OID_RF_DISCOVER_SELECT (0x04)
+#define NCI_OID_RF_INTF_ACTIVATED (0x05)
+#define NCI_OID_RF_DEACTIVATE (0x06)
+#define NCI_OID_RF_FIELD_INFO (0x07)
+#define NCI_OID_RF_T3T_POLLING (0x08)
+#define NCI_OID_RF_NFCEE_ACTION (0x09)
+#define NCI_OID_RF_NFCEE_DISCOVERY_REQ (0x0a)
+#define NCI_OID_RF_PARAMETER_UPDATE (0x0b)
+
+typedef struct nci_sm_io NciSmIo;
+
+struct nci_sm_io {
+ NciSar* sar;
+ gboolean (*send)(NciSmIo* io, guint8 gid, guint8 oid,
+ GBytes* payload, NciSmResponseFunc resp, gpointer user_data);
+ void (*cancel)(NciSmIo* io);
+};
+
+struct nci_sm {
+ NciSmIo* io;
+ NciState* last_state;
+ NciState* next_state;
+ GBytes* rf_interfaces;
+ guint max_routing_table_size;
+ NCI_INTERFACE_VERSION version;
+ NCI_NFCC_DISCOVERY nfcc_discovery;
+ NCI_NFCC_ROUTING nfcc_routing;
+ NCI_NFCC_POWER nfcc_power;
+};
+
+typedef
+void
+(*NciSmFunc)(
+ NciSm* sm,
+ void* user_data);
+
+typedef
+void
+(*NciSmIntfActivationFunc)(
+ NciSm* sm,
+ const NciIntfActivationNtf* ntf,
+ void* user_data);
+
+/* Universal interface, used all over the place */
+
+NciState*
+nci_sm_enter_state(
+ NciSm* sm,
+ NCI_STATE state,
+ NciParam* param);
+
+void
+nci_sm_switch_to(
+ NciSm* sm,
+ NCI_STATE id);
+
+void
+nci_sm_stall(
+ NciSm* sm,
+ NCI_STALL type);
+
+/* Interface for NciCore */
+
+NciSm*
+nci_sm_new(
+ NciSmIo* io);
+
+void
+nci_sm_free(
+ NciSm* sm);
+
+void
+nci_sm_handle_ntf(
+ NciSm* sm,
+ guint8 gid,
+ guint8 oid,
+ const GUtilData* payload);
+
+void
+nci_sm_add_state(
+ NciSm* sm,
+ NciState* state);
+
+void
+nci_sm_add_transition(
+ NciSm* sm,
+ NCI_STATE state,
+ NciTransition* transition);
+
+gulong
+nci_sm_add_last_state_handler(
+ NciSm* sm,
+ NciSmFunc func,
+ void* user_data);
+
+gulong
+nci_sm_add_next_state_handler(
+ NciSm* sm,
+ NciSmFunc func,
+ void* user_data);
+
+gulong
+nci_sm_add_intf_activated_handler(
+ NciSm* sm,
+ NciSmIntfActivationFunc func,
+ void* user_data);
+
+void
+nci_sm_remove_handler(
+ NciSm* sm,
+ gulong id);
+
+void
+nci_sm_remove_handlers(
+ NciSm* sm,
+ gulong* ids,
+ guint count);
+
+#define nci_sm_remove_all_handlers(sm,ids) \
+ nci_sm_remove_handlers(sm, ids, G_N_ELEMENTS(ids))
+
+/* Interface for states and transitions */
+
+void
+nci_sm_add_weak_pointer(
+ NciSm** ptr);
+
+void
+nci_sm_remove_weak_pointer(
+ NciSm** ptr);
+
+NciState*
+nci_sm_get_state(
+ NciSm* sm,
+ NCI_STATE state);
+
+NciSar*
+nci_sm_sar(
+ NciSm* sm);
+
+gboolean
+nci_sm_supports_protocol(
+ NciSm* sm,
+ NCI_PROTOCOL protocol);
+
+gboolean
+nci_sm_active_transition(
+ NciSm* sm,
+ NciTransition* transition);
+
+gboolean
+nci_sm_send_command(
+ NciSm* sm,
+ guint8 gid,
+ guint8 oid,
+ GBytes* payload,
+ NciSmResponseFunc resp,
+ gpointer user_data);
+
+gboolean
+nci_sm_send_command_static(
+ NciSm* sm,
+ guint8 gid,
+ guint8 oid,
+ const void* payload,
+ gsize payload_len,
+ NciSmResponseFunc resp,
+ gpointer user_data);
+
+void
+nci_sm_intf_activated(
+ NciSm* sm,
+ const NciIntfActivationNtf* ntf);
+
+void
+nci_sm_handle_conn_credits_ntf(
+ NciSm* sm,
+ const GUtilData* payload);
+
+void
+nci_sm_handle_rf_deactivate_ntf(
+ NciSm* sm,
+ const GUtilData* payload);
+
+#endif /* NCI_STATE_MACHINE_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_state.c
^
|
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "nci_state_p.h"
+#include "nci_state_impl.h"
+#include "nci_sm.h"
+#include "nci_transition.h"
+#include "nci_log.h"
+
+struct nci_state_priv {
+ NciSm* sm; /* Weak reference */
+ GHashTable* transitions;
+};
+
+G_DEFINE_TYPE(NciState, nci_state, G_TYPE_OBJECT)
+#define NCI_STATE_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), \
+ NCI_TYPE_STATE, NciStateClass)
+
+/*==========================================================================*
+ * Implementation
+ *==========================================================================*/
+
+static
+void
+nci_state_transition_gone(
+ gpointer state,
+ GObject* dead_transition)
+{
+ NciState* self = NCI_STATE(state);
+ NciStatePriv* priv = self->priv;
+ GHashTableIter it;
+ gpointer value;
+
+ g_hash_table_iter_init(&it, priv->transitions);
+ while (g_hash_table_iter_next(&it, NULL, &value)) {
+ if (dead_transition == value) {
+ g_hash_table_iter_remove(&it);
+ return;
+ }
+ }
+ GVERBOSE("Unexpected dead transition %p", dead_transition);
+}
+
+static
+void
+nci_state_generic_error_ntf(
+ NciState* self,
+ const GUtilData* payload)
+{
+ if (payload->size == 1) {
+ GWARN("Generic error 0x%02x", payload->bytes[0]);
+ } else {
+ GWARN("Failed to parse CORE_GENERIC_ERROR_NTF");
+ }
+}
+
+/*==========================================================================*
+ * Interface
+ *==========================================================================*/
+
+NciState*
+nci_state_ref(
+ NciState* self)
+{
+ if (G_LIKELY(self)) {
+ g_object_ref(NCI_STATE(self));
+ }
+ return self;
+}
+
+void
+nci_state_unref(
+ NciState* self)
+{
+ if (G_LIKELY(self)) {
+ g_object_unref(NCI_STATE(self));
+ }
+}
+
+/*==========================================================================*
+ * Internal states
+ *==========================================================================*/
+
+static
+NciState*
+nci_state_new(
+ NciSm* sm,
+ NCI_STATE state,
+ const char* name)
+{
+ NciState* self = g_object_new(NCI_TYPE_STATE, NULL);
+
+ nci_state_init_base(self, sm, state, name);
+ return self;
+}
+
+NciState*
+nci_state_init_new(
+ NciSm* sm)
+{
+ return nci_state_new(sm, NCI_STATE_INIT, "INIT");
+}
+
+NciState*
+nci_state_error_new(
+ NciSm* sm)
+{
+ return nci_state_new(sm, NCI_STATE_ERROR, "ERROR");
+}
+
+NciState*
+nci_state_stop_new(
+ NciSm* sm)
+{
+ return nci_state_new(sm, NCI_STATE_STOP, "STOP");
+}
+
+/*==========================================================================*
+ * Trivial states
+ *==========================================================================*/
+
+NciState*
+nci_state_idle_new(
+ NciSm* sm)
+{
+ return nci_state_new(sm, NCI_RFST_IDLE, "RFST_IDLE");
+}
+
+/*==========================================================================*
+ * Internal interface
+ *==========================================================================*/
+
+void
+nci_state_init_base(
+ NciState* self,
+ NciSm* sm,
+ NCI_STATE state,
+ const char* name)
+{
+ NciStatePriv* priv = self->priv;
+
+ /* Assume that name points to static buffer */
+ self->name = name;
+ self->state = state;
+ priv->sm = sm;
+ nci_sm_add_weak_pointer(&priv->sm);
+}
+
+gboolean
+nci_state_send_command(
+ NciState* self,
+ guint8 gid,
+ guint8 oid,
+ GBytes* payload,
+ NciSmResponseFunc resp,
+ gpointer user_data)
+{
+ return G_LIKELY(self) && nci_sm_send_command(self->priv->sm,
+ gid, oid, payload, resp, user_data);
+}
+
+NciSm*
+nci_state_sm(
+ NciState* self)
+{
+ return G_LIKELY(self) ? self->priv->sm : NULL;
+}
+
+void
+nci_state_add_transition(
+ NciState* self,
+ NciTransition* transition)
+{
+ if (G_LIKELY(self) && G_LIKELY(transition)) {
+ NciStatePriv* priv = self->priv;
+
+ g_hash_table_insert(priv->transitions,
+ GUINT_TO_POINTER(transition->dest->state), transition);
+ g_object_weak_ref(G_OBJECT(transition),
+ nci_state_transition_gone, self);
+ }
+}
+
+NciTransition*
+nci_state_get_transition(
+ NciState* self,
+ NCI_STATE dest)
+{
+ if (G_LIKELY(self)) {
+ NciStatePriv* priv = self->priv;
+
+ return g_hash_table_lookup(priv->transitions, GUINT_TO_POINTER(dest));
+ }
+ return NULL;
+}
+
+void
+nci_state_enter(
+ NciState* self,
+ void* param)
+{
+ if (G_LIKELY(self)) {
+ NCI_STATE_GET_CLASS(self)->enter(self, param);
+ }
+}
+
+void
+nci_state_reenter(
+ NciState* self,
+ void* param)
+{
+ if (G_LIKELY(self)) {
+ NCI_STATE_GET_CLASS(self)->reenter(self, param);
+ }
+}
+
+void
+nci_state_leave(
+ NciState* self)
+{
+ if (G_LIKELY(self)) {
+ NCI_STATE_GET_CLASS(self)->leave(self);
+ }
+}
+
+void
+nci_state_handle_ntf(
+ NciState* self,
+ guint8 gid,
+ guint8 oid,
+ const GUtilData* payload)
+{
+ if (G_LIKELY(self)) {
+ NCI_STATE_GET_CLASS(self)->handle_ntf(self, gid, oid, payload);
+ }
+}
+
+/*==========================================================================*
+ * Methods
+ *==========================================================================*/
+
+static
+void
+nci_state_default_enter(
+ NciState* self,
+ NciParam* param)
+{
+ GVERBOSE("Entered %s state", self->name);
+ self->active = TRUE;
+}
+
+static
+void
+nci_state_default_reenter(
+ NciState* self,
+ NciParam* param)
+{
+ GVERBOSE("Re-entered %s state", self->name);
+ GASSERT(self->active);
+}
+
+static
+void
+nci_state_default_leave(
+ NciState* self)
+{
+ GVERBOSE("Left %s state", self->name);
+ self->active = FALSE;
+}
+
+static
+void
+nci_state_default_handle_ntf(
+ NciState* self,
+ guint8 gid,
+ guint8 oid,
+ const GUtilData* payload)
+{
+ switch (gid) {
+ case NCI_GID_CORE:
+ switch (oid) {
+ case NCI_OID_CORE_CONN_CREDITS:
+ nci_sm_handle_conn_credits_ntf(nci_state_sm(self), payload);
+ return;
+ case NCI_OID_CORE_GENERIC_ERROR:
+ nci_state_generic_error_ntf(self, payload);
+ return;
+ }
+ break;
+ }
+ GDEBUG("Notification 0x%02x/0x%02x is ignored in %s state", gid, oid,
+ self->name);
+}
+
+/*==========================================================================*
+ * Internals
+ *==========================================================================*/
+
+static
+void
+nci_state_init(
+ NciState* self)
+{
+ NciStatePriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
+ NCI_TYPE_STATE, NciStatePriv);
+
+ self->priv = priv;
+ priv->transitions = g_hash_table_new(g_direct_hash, g_direct_equal);
+}
+
+static
+void
+nci_state_finalize(
+ GObject* object)
+{
+ NciState* self = NCI_STATE(object);
+ NciStatePriv* priv = self->priv;
+ GHashTableIter it;
+ gpointer value;
+
+ nci_sm_remove_weak_pointer(&priv->sm);
+ g_hash_table_iter_init(&it, priv->transitions);
+ while (g_hash_table_iter_next(&it, NULL, &value)) {
+ g_object_weak_unref(value, nci_state_transition_gone, self);
+ g_hash_table_iter_remove(&it);
+ }
+ g_hash_table_destroy(priv->transitions);
+ G_OBJECT_CLASS(nci_state_parent_class)->finalize(object);
+}
+
+static
+void
+nci_state_class_init(
+ NciStateClass* klass)
+{
+ g_type_class_add_private(klass, sizeof(NciStatePriv));
+ klass->enter = nci_state_default_enter;
+ klass->reenter = nci_state_default_reenter;
+ klass->leave = nci_state_default_leave;
+ klass->handle_ntf = nci_state_default_handle_ntf;
+ G_OBJECT_CLASS(klass)->finalize = nci_state_finalize;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_state_discovery.c
^
|
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "nci_sm.h"
+#include "nci_sar.h"
+#include "nci_state_impl.h"
+#include "nci_param_w4_all_discoveries.h"
+#include "nci_util.h"
+#include "nci_log.h"
+
+typedef NciState NciStateDiscovery;
+typedef NciStateClass NciStateDiscoveryClass;
+
+G_DEFINE_TYPE(NciStateDiscovery, nci_state_discovery, NCI_TYPE_STATE)
+#define THIS_TYPE (nci_state_discovery_get_type())
+#define PARENT_CLASS (nci_state_discovery_parent_class)
+
+/*==========================================================================*
+ * Implementation
+ *==========================================================================*/
+
+static
+void
+nci_state_discovery_intf_activated_ntf(
+ NciState* self,
+ const GUtilData* payload)
+{
+ NciIntfActivationNtf ntf;
+ NciModeParam mode_param;
+ NciActivationParam activation_param;
+ NciSm* sm = nci_state_sm(self);
+
+ /*
+ * 5.2.2 State RFST_DISCOVERY
+ *
+ * ...
+ * While polling, if the NFCC discovers just one Remote NFC Endpoint
+ * that supports just one Protocol, the NFCC SHALL try to automatically
+ * activate it. The NFCC SHALL first establish any underlying protocol(s)
+ * with the Remote NFC Endpoint that are needed by the configured RF
+ * Interface. On completion, the NFCC SHALL activate the RF Interface
+ * and send RF_INTF_ACTIVATED_NTF (Poll Mode) to the DH. At this point,
+ * the state is changed to RFST_POLL_ACTIVE.
+ */
+ if (nci_parse_intf_activated_ntf(&ntf, &mode_param, &activation_param,
+ payload->bytes, payload->size)) {
+ nci_sm_intf_activated(sm, &ntf);
+ nci_sm_enter_state(sm, NCI_RFST_POLL_ACTIVE, NULL);
+ } else {
+ /* Deactivate this target */
+ nci_sm_enter_state(sm, NCI_RFST_POLL_ACTIVE, NULL);
+ nci_sm_switch_to(sm, NCI_RFST_DISCOVERY);
+ }
+}
+
+static
+void
+nci_state_discovery_discover_ntf(
+ NciState* self,
+ const GUtilData* payload)
+{
+ NciDiscoveryNtf ntf;
+ NciModeParam param;
+
+ /*
+ * 5.2.2 State RFST_DISCOVERY
+ *
+ * ...
+ * While polling, if the NFCC discovers more than one Remote NFC Endpoint,
+ * or a Remote NFC Endpoint that supports more than one RF Protocol, it
+ * SHALL start sending RF_DISCOVER_NTF messages to the DH. At this point,
+ * the state is changed to RFST_W4_ALL_DISCOVERIES.
+ */
+ if (nci_parse_discover_ntf(&ntf, ¶m, payload->bytes, payload->size)) {
+ NciSm* sm = nci_state_sm(self);
+ NciParam* param = NCI_PARAM(nci_param_w4_all_discoveries_new(&ntf));
+
+ nci_sm_enter_state(sm, NCI_RFST_W4_ALL_DISCOVERIES, param);
+ nci_param_unref(param);
+ }
+}
+
+static
+gboolean
+nci_state_discovery_generic_error_ntf(
+ NciState* self,
+ const GUtilData* payload)
+{
+ const guint8* pkt = payload->bytes;
+ const guint len = payload->size;
+
+ /*
+ * Table 18: Control Messages for Generic Error
+ *
+ * CORE_GENERIC_ERROR_NTF
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | Status |
+ * +=========================================================+
+ *
+ * 5.2.2 State RFST_DISCOVERY
+ *
+ * ...
+ * If the protocol activation is not successful, the NFCC SHALL
+ * send CORE_GENERIC_ERROR_NTF to the DH with status
+ * DISCOVERY_TARGET_ACTIVATION_FAILED and stay in RFST_DISCOVERY.
+ *
+ * In this state, the NFCC MAY detect a command during the RF
+ * communication, which forces it to come back to the IDLE state,
+ * as defined in the [NFC Forum Activity Technical Specification]
+ * Listen Mode state machine. If the RF Protocol deactivation is
+ * completed, the NFCC SHALL send CORE_GENERIC_ERROR_NTF
+ * (DISCOVERY_TEAR_DOWN), and the state will remain RFST_DISCOVERY.
+ */
+ if (len == 1) {
+ switch (pkt[0]) {
+ case NCI_DISCOVERY_TARGET_ACTIVATION_FAILED:
+ GDEBUG("CORE_GENERIC_ERROR_NTF (Activation Failed)");
+ return TRUE;
+ case NCI_DISCOVERY_TEAR_DOWN:
+ GDEBUG("CORE_GENERIC_ERROR_NTF (Tear Down)");
+ return TRUE;
+ }
+ }
+ /* Unrecornized notification */
+ return FALSE;
+}
+
+/*==========================================================================*
+ * Interface
+ *==========================================================================*/
+
+NciState*
+nci_state_discovery_new(
+ NciSm* sm)
+{
+ NciState* self = g_object_new(THIS_TYPE, NULL);
+
+ nci_state_init_base(self, sm, NCI_RFST_DISCOVERY, "RFST_DISCOVERY");
+ return self;
+}
+
+/*==========================================================================*
+ * Methods
+ *==========================================================================*/
+
+static
+void
+nci_state_discovery_handle_ntf(
+ NciState* self,
+ guint8 gid,
+ guint8 oid,
+ const GUtilData* payload)
+{
+ switch (gid) {
+ case NCI_GID_CORE:
+ switch (oid) {
+ case NCI_OID_CORE_GENERIC_ERROR:
+ if (nci_state_discovery_generic_error_ntf(self, payload)) {
+ return;
+ }
+ }
+ break;
+ case NCI_GID_RF:
+ switch (oid) {
+ case NCI_OID_RF_DISCOVER:
+ nci_state_discovery_discover_ntf(self, payload);
+ return;
+ case NCI_OID_RF_INTF_ACTIVATED:
+ nci_state_discovery_intf_activated_ntf(self, payload);
+ return;
+ case NCI_OID_RF_DEACTIVATE:
+ nci_sm_handle_rf_deactivate_ntf(nci_state_sm(self), payload);
+ return;
+ }
+ break;
+ }
+ NCI_STATE_CLASS(PARENT_CLASS)->handle_ntf(self, gid, oid, payload);
+}
+
+/*==========================================================================*
+ * Internals
+ *==========================================================================*/
+
+static
+void
+nci_state_discovery_init(
+ NciStateDiscovery* self)
+{
+}
+
+static
+void
+nci_state_discovery_class_init(
+ NciStateDiscoveryClass* klass)
+{
+ NCI_STATE_CLASS(klass)->handle_ntf = nci_state_discovery_handle_ntf;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_state_impl.h
^
|
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NCI_STATE_IMPL_H
+#define NCI_STATE_IMPL_H
+
+#include "nci_state.h"
+#include "nci_types_p.h"
+
+/* Internal API for use by NciState implemenations */
+
+typedef struct nci_state_class {
+ GObjectClass parent;
+ void (*enter)(NciState* state, NciParam* param);
+ void (*reenter)(NciState* state, NciParam* param);
+ void (*leave)(NciState* state);
+ void (*handle_ntf)(NciState* state, guint8 gid, guint8 oid,
+ const GUtilData* payload);
+} NciStateClass;
+
+#define NCI_STATE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), \
+ NCI_TYPE_STATE, NciStateClass)
+
+void
+nci_state_init_base(
+ NciState* state,
+ NciSm* sm,
+ NCI_STATE id,
+ const char* name);
+
+gboolean
+nci_state_send_command(
+ NciState* state,
+ guint8 gid,
+ guint8 oid,
+ GBytes* payload,
+ NciSmResponseFunc resp,
+ gpointer user_data);
+
+void
+nci_state_error(
+ NciState* state);
+
+NciSm*
+nci_state_sm(
+ NciState* state);
+
+#endif /* NCI_STATE_IMPL_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_state_p.h
^
|
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NCI_STATE_PRIVATE_H
+#define NCI_STATE_PRIVATE_H
+
+#include "nci_types_p.h"
+
+#include "nci_state.h"
+
+NciTransition*
+nci_state_get_transition(
+ NciState* state,
+ NCI_STATE dest);
+
+void
+nci_state_add_transition(
+ NciState* state,
+ NciTransition* transition);
+
+void
+nci_state_enter(
+ NciState* state,
+ void* param);
+
+void
+nci_state_reenter(
+ NciState* state,
+ void* param);
+
+void
+nci_state_leave(
+ NciState* state);
+
+void
+nci_state_handle_ntf(
+ NciState* state,
+ guint8 gid,
+ guint8 oid,
+ const GUtilData* payload);
+
+/* Specific states */
+
+NciState* /* NCI_STATE_INIT */
+nci_state_init_new(
+ NciSm* sm);
+
+NciState* /* NCI_STATE_ERROR */
+nci_state_error_new(
+ NciSm* sm);
+
+NciState* /* NCI_STATE_STOP */
+nci_state_stop_new(
+ NciSm* sm);
+
+NciState* /* NCI_RFST_IDLE */
+nci_state_idle_new(
+ NciSm* sm);
+
+NciState* /* NCI_RFST_DISCOVERY */
+nci_state_discovery_new(
+ NciSm* sm);
+
+NciState* /* NCI_RFST_POLL_ACTIVE */
+nci_state_poll_active_new(
+ NciSm* sm);
+
+NciState* /* NCI_RFST_W4_ALL_DISCOVERIES */
+nci_state_w4_all_discoveries_new(
+ NciSm* sm);
+
+NciState* /* NCI_RFST_W4_HOST_SELECT */
+nci_state_w4_host_select_new(
+ NciSm* sm);
+
+#endif /* NCI_STATE_PRIVATE_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_state_poll_active.c
^
|
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "nci_sm.h"
+#include "nci_state_impl.h"
+#include "nci_log.h"
+
+typedef NciState NciStatePollActive;
+typedef NciStateClass NciStatePollActiveClass;
+
+G_DEFINE_TYPE(NciStatePollActive, nci_state_poll_active, NCI_TYPE_STATE)
+#define THIS_TYPE (nci_state_poll_active_get_type())
+#define PARENT_CLASS (nci_state_poll_active_parent_class)
+
+/*==========================================================================*
+ * Implementation
+ *==========================================================================*/
+
+static
+gboolean
+nci_state_poll_active_interface_error_ntf(
+ NciState* self,
+ const GUtilData* payload)
+{
+ const guint8* pkt = payload->bytes;
+ const guint len = payload->size;
+
+ /*
+ * Table 19: Control Messages for Interface Error
+ *
+ * CORE_INTERFACE_ERROR_NTF
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | Status |
+ * | 1 | 1 | Conn ID |
+ * +=========================================================+
+ *
+ * 5.2.5 State RFST_POLL_ACTIVE
+ *
+ * ...
+ * When using the ISO-DEP or NFC-DEP RF interface, and the NFCC
+ * detects an error during the RF communication, it SHALL notify
+ * the DH sending CORE_INTERFACE_ERROR_NTF, using the appropriate
+ * status out of RF_TRANSMISSION_ERROR, RF_PROTOCOL_ERROR and
+ * RF_TIMEOUT_ERROR. The state will then remain RFST_POLL_ACTIVE.
+ */
+ if (len == 2) {
+ switch (pkt[0]) {
+ case NCI_RF_TRANSMISSION_ERROR:
+ GDEBUG("CORE_INTERFACE_ERROR_NTF (Transmission Error)");
+ return TRUE;
+ case NCI_RF_PROTOCOL_ERROR:
+ GDEBUG("CORE_INTERFACE_ERROR_NTF (Protocol Error)");
+ return TRUE;
+ case NCI_RF_TIMEOUT_ERROR:
+ GDEBUG("CORE_INTERFACE_ERROR_NTF (Timeout)");
+ return TRUE;
+ }
+ }
+ /* Unrecornized notification */
+ return FALSE;
+}
+
+/*==========================================================================*
+ * Interface
+ *==========================================================================*/
+
+NciState*
+nci_state_poll_active_new(
+ NciSm* sm)
+{
+ NciState* self = g_object_new(THIS_TYPE, NULL);
+
+ nci_state_init_base(self, sm, NCI_RFST_POLL_ACTIVE, "RFST_POLL_ACTIVE");
+ return self;
+}
+
+/*==========================================================================*
+ * Methods
+ *==========================================================================*/
+
+static
+void
+nci_state_poll_active_handle_ntf(
+ NciState* state,
+ guint8 gid,
+ guint8 oid,
+ const GUtilData* payload)
+{
+ switch (gid) {
+ case NCI_GID_CORE:
+ switch (oid) {
+ case NCI_OID_CORE_INTERFACE_ERROR:
+ if (nci_state_poll_active_interface_error_ntf(state, payload)) {
+ return;
+ }
+ break;
+ }
+ break;
+ case NCI_GID_RF:
+ switch (oid) {
+ case NCI_OID_RF_DEACTIVATE:
+ nci_sm_handle_rf_deactivate_ntf(nci_state_sm(state), payload);
+ return;
+ }
+ break;
+ }
+ NCI_STATE_CLASS(PARENT_CLASS)->handle_ntf(state, gid, oid, payload);
+}
+
+/*==========================================================================*
+ * Internals
+ *==========================================================================*/
+
+static
+void
+nci_state_poll_active_init(
+ NciStatePollActive* self)
+{
+}
+
+static
+void
+nci_state_poll_active_class_init(
+ NciStatePollActiveClass* klass)
+{
+ NCI_STATE_CLASS(klass)->handle_ntf = nci_state_poll_active_handle_ntf;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_state_w4_all_discoveries.c
^
|
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "nci_sm.h"
+#include "nci_state_impl.h"
+#include "nci_param_w4_all_discoveries.h"
+#include "nci_param_w4_host_select.h"
+#include "nci_util.h"
+
+typedef NciStateClass NciStateW4AllDiscoveriesClass;
+typedef struct nci_state_w4_all_discoveries {
+ NciState state;
+ GPtrArray* discoveries;
+} NciStateW4AllDiscoveries;
+
+G_DEFINE_TYPE(NciStateW4AllDiscoveries, nci_state_w4_all_discoveries,
+ NCI_TYPE_STATE)
+#define THIS_TYPE (nci_state_w4_all_discoveries_get_type())
+#define PARENT_CLASS (nci_state_w4_all_discoveries_parent_class)
+#define NCI_STATE_W4_ALL_DISCOVERIES(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ THIS_TYPE, NciStateW4AllDiscoveries))
+
+/*==========================================================================*
+ * Implementation
+ *==========================================================================*/
+
+static
+void
+nci_state_w4_all_discoveries_handle_discovery(
+ NciStateW4AllDiscoveries* self,
+ const NciDiscoveryNtf* ntf)
+{
+ /* Store discovery info in self->discoveries */
+ g_ptr_array_add(self->discoveries, nci_discovery_ntf_copy(ntf));
+
+ /*
+ * 5.2.3 State RFST_W4_ALL_DISCOVERIES
+ *
+ * ...
+ * Discover notifications with Notification type set to 2 SHALL NOT
+ * change the state. When the NFCC sends the last RF_DISCOVER_NTF
+ * (Notification Type not equal to 2) to the DH, the state is
+ * changed to RFST_W4_HOST_SELECT.
+ */
+ if (ntf->last) {
+ NciSm* sm = nci_state_sm(&self->state);
+ NciParam* param = NCI_PARAM(nci_param_w4_host_select_new(
+ (const NciDiscoveryNtf**)self->discoveries->pdata,
+ self->discoveries->len));
+
+ nci_sm_enter_state(sm, NCI_RFST_W4_HOST_SELECT, param);
+ nci_param_unref(param);
+ }
+}
+
+static
+void
+nci_state_w4_all_discoveries_start(
+ NciStateW4AllDiscoveries* self,
+ NciParam* param)
+{
+ g_ptr_array_set_size(self->discoveries, 0);
+ if (NCI_IS_PARAM_W4_ALL_DISCOVERIES(param)) {
+ nci_param_ref(param);
+ nci_state_w4_all_discoveries_handle_discovery(self,
+ NCI_PARAM_W4_ALL_DISCOVERIES(param)->ntf);
+ nci_param_unref(param);
+ }
+}
+
+static
+void
+nci_state_w4_all_discoveries_discover_ntf(
+ NciStateW4AllDiscoveries* self,
+ const GUtilData* payload)
+{
+ NciDiscoveryNtf ntf;
+ NciModeParam param;
+
+ if (nci_parse_discover_ntf(&ntf, ¶m, payload->bytes, payload->size)) {
+ nci_state_w4_all_discoveries_handle_discovery(self, &ntf);
+ }
+}
+
+/*==========================================================================*
+ * Interface
+ *==========================================================================*/
+
+NciState*
+nci_state_w4_all_discoveries_new(
+ NciSm* sm)
+{
+ NciState* self = g_object_new(THIS_TYPE, NULL);
+
+ nci_state_init_base(self, sm, NCI_RFST_W4_ALL_DISCOVERIES,
+ "RFST_W4_ALL_DISCOVERIES");
+ return self;
+}
+
+/*==========================================================================*
+ * Methods
+ *==========================================================================*/
+
+static
+void
+nci_state_w4_all_discoveries_enter(
+ NciState* state,
+ NciParam* param)
+{
+ NciStateW4AllDiscoveries* self = NCI_STATE_W4_ALL_DISCOVERIES(state);
+
+ nci_state_w4_all_discoveries_start(self, param);
+ NCI_STATE_CLASS(PARENT_CLASS)->enter(state, param);
+}
+
+static
+void
+nci_state_w4_all_discoveries_reenter(
+ NciState* state,
+ NciParam* param)
+{
+ NciStateW4AllDiscoveries* self = NCI_STATE_W4_ALL_DISCOVERIES(state);
+
+ nci_state_w4_all_discoveries_start(self, param);
+ NCI_STATE_CLASS(PARENT_CLASS)->reenter(state, param);
+}
+
+static
+void
+nci_state_w4_all_discoveries_leave(
+ NciState* state)
+{
+ NciStateW4AllDiscoveries* self = NCI_STATE_W4_ALL_DISCOVERIES(state);
+
+ /* Release the memory */
+ g_ptr_array_set_size(self->discoveries, 0);
+ NCI_STATE_CLASS(PARENT_CLASS)->leave(state);
+}
+
+static
+void
+nci_state_w4_all_discoveries_handle_ntf(
+ NciState* state,
+ guint8 gid,
+ guint8 oid,
+ const GUtilData* payload)
+{
+ switch (gid) {
+ case NCI_GID_RF:
+ switch (oid) {
+ case NCI_OID_RF_DISCOVER:
+ nci_state_w4_all_discoveries_discover_ntf
+ (NCI_STATE_W4_ALL_DISCOVERIES(state), payload);
+ return;
+ }
+ break;
+ }
+ NCI_STATE_CLASS(PARENT_CLASS)->handle_ntf(state, gid, oid, payload);
+}
+
+/*==========================================================================*
+ * Internals
+ *==========================================================================*/
+
+static
+void
+nci_state_w4_all_discoveries_init(
+ NciStateW4AllDiscoveries* self)
+{
+ self->discoveries = g_ptr_array_new_with_free_func(g_free);
+}
+
+static
+void
+nci_state_w4_all_discoveries_finalize(
+ GObject* object)
+{
+ NciStateW4AllDiscoveries* self = NCI_STATE_W4_ALL_DISCOVERIES(object);
+
+ g_ptr_array_free(self->discoveries, TRUE);
+ G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
+}
+
+static
+void
+nci_state_w4_all_discoveries_class_init(
+ NciStateW4AllDiscoveriesClass* klass)
+{
+ klass->enter = nci_state_w4_all_discoveries_enter;
+ klass->reenter = nci_state_w4_all_discoveries_reenter;
+ klass->leave = nci_state_w4_all_discoveries_leave;
+ klass->handle_ntf = nci_state_w4_all_discoveries_handle_ntf;
+ G_OBJECT_CLASS(klass)->finalize = nci_state_w4_all_discoveries_finalize;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_state_w4_host_select.c
^
|
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "nci_sm.h"
+#include "nci_state_impl.h"
+#include "nci_param_w4_host_select.h"
+#include "nci_util.h"
+#include "nci_log.h"
+
+typedef NciStateClass NciStateW4HostSelectClass;
+typedef NciState NciStateW4HostSelect;
+
+G_DEFINE_TYPE(NciStateW4HostSelect, nci_state_w4_host_select, NCI_TYPE_STATE)
+#define THIS_TYPE (nci_state_w4_host_select_get_type())
+#define PARENT_CLASS (nci_state_w4_host_select_parent_class)
+#define NCI_STATE_W4_HOST_SELECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ THIS_TYPE, NciStateW4HostSelect))
+
+/*==========================================================================*
+ * Implementation
+ *==========================================================================*/
+
+static
+gint
+nci_state_w4_host_select_sort(
+ gconstpointer a,
+ gconstpointer b)
+{
+ const NciDiscoveryNtf* ntf_a = a;
+ const NciDiscoveryNtf* ntf_b = b;
+
+ /*
+ * Return 0 if elements are equal, a negative value if the
+ * first element comes before the second, or a positive value if
+ * the first element comes after the second.
+ */
+ if (ntf_a->protocol != ntf_b->protocol) {
+ static const NCI_PROTOCOL protocol_order[] = {
+ NCI_PROTOCOL_T2T,
+ NCI_PROTOCOL_ISO_DEP
+ };
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS(protocol_order); i++) {
+ if (ntf_a->protocol == protocol_order[i]) {
+ return -1;
+ } else if (ntf_b->protocol == protocol_order[i]) {
+ return 1;
+ }
+ }
+ }
+
+ /* Otherwise sort by discovery ID */
+ return (gint)(ntf_a->discovery_id) - (gint)(ntf_b->discovery_id);
+}
+
+static
+void
+nci_state_w4_host_select_rsp(
+ NCI_REQUEST_STATUS status,
+ const GUtilData* payload,
+ gpointer user_data)
+{
+ if (status == NCI_REQUEST_SUCCESS) {
+ const guint8* pkt = payload->bytes;
+ const guint len = payload->size;
+
+ /*
+ * Table 60: Control Messages to select a Discovered Target
+ *
+ * RF_DISCOVER_SELECT_RSP
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | Status |
+ * +=========================================================+
+ */
+ if (len > 0 && pkt[0] == NCI_STATUS_OK) {
+ GDEBUG("%c RF_DISCOVER_SELECT_RSP ok", DIR_IN);
+ } else {
+ if (len > 0) {
+ GWARN("%c RF_DISCOVER_SELECT_RSP error %u", DIR_IN, pkt[0]);
+ } else {
+ GWARN("%c Broken RF_DISCOVER_SELECT_RSP", DIR_IN);
+ }
+ }
+ } else {
+ GWARN("RF_DISCOVER_SELECT failed");
+ }
+}
+
+static
+void
+nci_state_w4_host_select_entered(
+ NciStateW4HostSelect* self,
+ NciParam* param)
+{
+ if (NCI_IS_PARAM_W4_HOST_SELECT(param)) {
+ NciSm* sm = nci_state_sm(self);
+ NciParamW4HostSelect* select = NCI_PARAM_W4_HOST_SELECT(param);
+ GSList* selected = NULL;
+ guint i;
+
+ /* Select a supported protocol */
+ for (i = 0; i < select->count; i++) {
+ NciDiscoveryNtf* ntf = select->ntf + i;
+
+ if (nci_sm_supports_protocol(sm, ntf->protocol)) {
+ selected = g_slist_insert_sorted(selected, ntf,
+ nci_state_w4_host_select_sort);
+ }
+ }
+
+ /*
+ * We may want to store the list and selected the next protocol
+ * if the best one gets rejected.
+ */
+ if (selected) {
+ const NciDiscoveryNtf* ntf = selected->data;
+ GBytes* payload;
+
+ /*
+ * Table 60: Control Messages to select a Discovered Target
+ *
+ * RF_DISCOVER_SELECT_CMD
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | RF Discovery ID |
+ * | 1 | 1 | RF Protocol |
+ * | 2 | 1 | RF Interface |
+ * +=========================================================+
+ */
+ guint8 cmd[3];
+ cmd[0] = ntf->discovery_id;
+ cmd[1] = ntf->protocol;
+ cmd[2] = (ntf->protocol == NCI_PROTOCOL_ISO_DEP) ?
+ NCI_RF_INTERFACE_ISO_DEP :
+ NCI_RF_INTERFACE_FRAME;
+
+ GDEBUG("%c RF_DISCOVER_SELECT_CMD (0x%02x)", DIR_OUT,
+ ntf->discovery_id);
+ payload = g_bytes_new(cmd, sizeof(cmd));
+ nci_sm_send_command(sm, NCI_GID_RF, NCI_OID_RF_DISCOVER_SELECT,
+ payload, nci_state_w4_host_select_rsp, self);
+ g_bytes_unref(payload);
+ g_slist_free(selected);
+ }
+ }
+}
+
+static
+void
+nci_state_w4_host_select_handle_intf_activated_ntf(
+ NciState* self,
+ const GUtilData* payload)
+{
+ NciIntfActivationNtf ntf;
+ NciModeParam mode_param;
+ NciActivationParam activation_param;
+ NciSm* sm = nci_state_sm(self);
+
+ /*
+ * 5.2.4 State RFST_W4_HOST_SELECT
+ *
+ * ...
+ * When the DH sends RF_DISCOVER_SELECT_CMD with a valid RF Discovery
+ * ID, RF Protocol and RF Interface, the NFCC SHALL try to activate
+ * the associated Remote NFC Endpoint (depending on the state of the
+ * Remote NFC Endpoint). The NFCC SHALL first establish any underlying
+ * protocol(s) with the Remote NFC Endpoint that are needed by the
+ * configured RF Interface. On completion, the NFCC SHALL activate
+ * the RF Interface and send RF_INTF_ACTIVATED_NTF (Poll Mode) to
+ * the DH. At this point, the state is changed to RFST_POLL_ACTIVE.
+ */
+ if (nci_parse_intf_activated_ntf(&ntf, &mode_param, &activation_param,
+ payload->bytes, payload->size)) {
+ nci_sm_intf_activated(sm, &ntf);
+ nci_sm_enter_state(sm, NCI_RFST_POLL_ACTIVE, NULL);
+ } else {
+ /* Deactivate this target */
+ nci_sm_enter_state(sm, NCI_RFST_POLL_ACTIVE, NULL);
+ nci_sm_switch_to(sm, NCI_RFST_DISCOVERY);
+ }
+}
+
+static
+gboolean
+nci_state_w4_host_select_generic_error_ntf(
+ NciState* self,
+ const GUtilData* payload)
+{
+ const guint8* pkt = payload->bytes;
+ const guint len = payload->size;
+
+ /*
+ * Table 18: Control Messages for Generic Error
+ *
+ * CORE_GENERIC_ERROR_NTF
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | Status |
+ * +=========================================================+
+ *
+ * 5.2.4 State RFST_W4_HOST_SELECT
+ *
+ * ...
+ * If the activation was not successful, the NFCC SHALL
+ * send CORE_GENERIC_ERROR_NTF to the DH with a Status of
+ * DISCOVERY_TARGET_ACTIVATION_FAILED and the state will
+ * remain as RFST_W4_HOST_SELECT.
+ */
+ if (len == 1) {
+ switch (pkt[0]) {
+ case NCI_DISCOVERY_TARGET_ACTIVATION_FAILED:
+ GDEBUG("CORE_GENERIC_ERROR_NTF (Activation Failed)");
+ return TRUE;
+ }
+ }
+ /* Unrecornized notification */
+ return FALSE;
+}
+
+/*==========================================================================*
+ * Interface
+ *==========================================================================*/
+
+NciState*
+nci_state_w4_host_select_new(
+ NciSm* sm)
+{
+ NciState* self = g_object_new(THIS_TYPE, NULL);
+
+ nci_state_init_base(self, sm, NCI_RFST_W4_HOST_SELECT,
+ "RFST_W4_HOST_SELECT");
+ return self;
+}
+
+/*==========================================================================*
+ * Methods
+ *==========================================================================*/
+
+static
+void
+nci_state_w4_host_select_enter(
+ NciState* self,
+ NciParam* param)
+{
+ nci_state_w4_host_select_entered(self, param);
+ NCI_STATE_CLASS(PARENT_CLASS)->enter(self, param);
+}
+
+static
+void
+nci_state_w4_host_select_reenter(
+ NciState* self,
+ NciParam* param)
+{
+ nci_state_w4_host_select_entered(self, param);
+ NCI_STATE_CLASS(PARENT_CLASS)->reenter(self, param);
+}
+
+static
+void
+nci_state_w4_host_select_handle_ntf(
+ NciState* self,
+ guint8 gid,
+ guint8 oid,
+ const GUtilData* payload)
+{
+ switch (gid) {
+ case NCI_GID_CORE:
+ switch (oid) {
+ case NCI_OID_CORE_GENERIC_ERROR:
+ if (nci_state_w4_host_select_generic_error_ntf(self, payload)) {
+ return;
+ }
+ }
+ break;
+ case NCI_GID_RF:
+ switch (oid) {
+ case NCI_OID_RF_INTF_ACTIVATED:
+ nci_state_w4_host_select_handle_intf_activated_ntf(self, payload);
+ return;
+ }
+ break;
+ }
+ NCI_STATE_CLASS(PARENT_CLASS)->handle_ntf(self, gid, oid, payload);
+}
+
+/*==========================================================================*
+ * Internals
+ *==========================================================================*/
+
+static
+void
+nci_state_w4_host_select_init(
+ NciStateW4HostSelect* self)
+{
+}
+
+static
+void
+nci_state_w4_host_select_class_init(
+ NciStateW4HostSelectClass* klass)
+{
+ klass->enter = nci_state_w4_host_select_enter;
+ klass->reenter = nci_state_w4_host_select_reenter;
+ klass->handle_ntf = nci_state_w4_host_select_handle_ntf;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_transition.c
^
|
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "nci_transition.h"
+#include "nci_transition_impl.h"
+#include "nci_state.h"
+#include "nci_sm.h"
+#include "nci_log.h"
+
+struct nci_transition_priv {
+ NciSm* sm; /* Weak reference */
+};
+
+G_DEFINE_ABSTRACT_TYPE(NciTransition, nci_transition, G_TYPE_OBJECT)
+#define NCI_TRANSITION_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), \
+ NCI_TYPE_TRANSITION, NciTransitionClass)
+
+/*==========================================================================*
+ * Interface
+ *==========================================================================*/
+
+NciTransition*
+nci_transition_ref(
+ NciTransition* self)
+{
+ if (G_LIKELY(self)) {
+ g_object_ref(NCI_TRANSITION(self));
+ }
+ return self;
+}
+
+void
+nci_transition_unref(
+ NciTransition* self)
+{
+ if (G_LIKELY(self)) {
+ g_object_unref(NCI_TRANSITION(self));
+ }
+}
+
+void
+nci_transition_init_base(
+ NciTransition* self,
+ NciSm* sm,
+ NciState* dest)
+{
+ NciTransitionPriv* priv = self->priv;
+
+ self->dest = nci_state_ref(dest);
+ priv->sm = sm;
+ nci_sm_add_weak_pointer(&priv->sm);
+}
+
+NciSm*
+nci_transition_sm(
+ NciTransition* self)
+{
+ return G_LIKELY(self) ? self->priv->sm : NULL;
+}
+
+void
+nci_transition_stall(
+ NciTransition* self,
+ NCI_STALL stall)
+{
+ nci_sm_stall(nci_transition_sm(self), stall);
+}
+
+gboolean
+nci_transition_active(
+ NciTransition* self)
+{
+ return nci_sm_active_transition(nci_transition_sm(self), self);
+}
+
+void
+nci_transition_finish(
+ NciTransition* self,
+ void* param)
+{
+ if (G_LIKELY(self)) {
+ nci_sm_enter_state(self->priv->sm, self->dest->state, param);
+ }
+}
+
+gboolean
+nci_transition_start(
+ NciTransition* self)
+{
+ if (G_LIKELY(self)) {
+ if (NCI_TRANSITION_GET_CLASS(self)->start(self)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void
+nci_transition_finished(
+ NciTransition* self)
+{
+ if (G_LIKELY(self)) {
+ NCI_TRANSITION_GET_CLASS(self)->finished(self);
+ }
+}
+
+void
+nci_transition_handle_ntf(
+ NciTransition* self,
+ guint8 gid,
+ guint8 oid,
+ const GUtilData* payload)
+{
+ if (G_LIKELY(self)) {
+ NCI_TRANSITION_GET_CLASS(self)->handle_ntf(self, gid, oid, payload);
+ }
+}
+
+gboolean
+nci_transition_send_command(
+ NciTransition* self,
+ guint8 gid,
+ guint8 oid,
+ GBytes* payload,
+ NciTransitionResponseFunc resp)
+{
+ return G_LIKELY(self) && nci_sm_send_command(self->priv->sm,
+ gid, oid, payload, (NciSmResponseFunc)resp, self);
+}
+
+gboolean
+nci_transition_send_command_static(
+ NciTransition* self,
+ guint8 gid,
+ guint8 oid,
+ const void* payload,
+ gsize payload_len,
+ NciTransitionResponseFunc resp)
+{
+ return G_LIKELY(self) && nci_sm_send_command_static(self->priv->sm,
+ gid, oid, payload, payload_len, (NciSmResponseFunc)resp, self);
+}
+
+/*
+ * Table 62: Control Messages for RF Interface Deactivation
+ *
+ * RF_DEACTIVATE_CMD
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | Deactivation Type |
+ * +=========================================================+
+ */
+gboolean
+nci_transition_deactivate_to_idle(
+ NciTransition* self,
+ NciTransitionResponseFunc resp)
+{
+ static const guint8 cmd[] = { NCI_DEACTIVATE_TYPE_IDLE };
+
+ GDEBUG("%c RF_DEACTIVATE_CMD (Idle)", DIR_OUT);
+ return nci_transition_send_command_static(self, NCI_GID_RF,
+ NCI_OID_RF_DEACTIVATE, cmd, sizeof(cmd), resp);
+}
+
+gboolean
+nci_transition_deactivate_to_discovery(
+ NciTransition* self,
+ NciTransitionResponseFunc resp)
+{
+ static const guint8 cmd[] = { NCI_DEACTIVATE_TYPE_DISCOVERY };
+
+ GDEBUG("%c RF_DEACTIVATE_CMD (Discovery)", DIR_OUT);
+ return nci_transition_send_command_static(self, NCI_GID_RF,
+ NCI_OID_RF_DEACTIVATE, cmd, sizeof(cmd), resp);
+}
+
+/*==========================================================================*
+ * Methods
+ *==========================================================================*/
+
+static
+gboolean
+nci_transition_default_start(
+ NciTransition* self)
+{
+ GERR("Non-startable transition!");
+ return FALSE;
+}
+
+static
+void
+nci_transition_default_finished(
+ NciTransition* self)
+{
+}
+
+static
+void
+nci_transition_default_handle_ntf(
+ NciTransition* self,
+ guint8 gid,
+ guint8 oid,
+ const GUtilData* payload)
+{
+ GDEBUG("Notification 0x%02x/0x%02x is ignored in transition", gid, oid);
+}
+
+/*==========================================================================*
+ * Internals
+ *==========================================================================*/
+
+static
+void
+nci_transition_init(
+ NciTransition* self)
+{
+ NciTransitionPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
+ NCI_TYPE_TRANSITION, NciTransitionPriv);
+
+ self->priv = priv;
+}
+
+static
+void
+nci_transition_finalize(
+ GObject* object)
+{
+ NciTransition* self = NCI_TRANSITION(object);
+ NciTransitionPriv* priv = self->priv;
+
+ nci_state_unref(self->dest);
+ nci_sm_remove_weak_pointer(&priv->sm);
+ G_OBJECT_CLASS(nci_transition_parent_class)->finalize(object);
+}
+
+static
+void
+nci_transition_class_init(
+ NciTransitionClass* klass)
+{
+ g_type_class_add_private(klass, sizeof(NciTransitionPriv));
+ klass->start = nci_transition_default_start;
+ klass->finished = nci_transition_default_finished;
+ klass->handle_ntf = nci_transition_default_handle_ntf;
+ G_OBJECT_CLASS(klass)->finalize = nci_transition_finalize;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_transition.h
^
|
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NCI_TRANSITION_H
+#define NCI_TRANSITION_H
+
+#include "nci_types_p.h"
+
+#include <glib-object.h>
+
+/* State transition */
+
+typedef struct nci_transition_priv NciTransitionPriv;
+
+struct nci_transition {
+ GObject object;
+ NciTransitionPriv* priv;
+ NciState* dest;
+};
+
+GType nci_transition_get_type(void);
+#define NCI_TYPE_TRANSITION (nci_transition_get_type())
+#define NCI_TRANSITION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ NCI_TYPE_TRANSITION, NciTransition))
+
+typedef
+void
+(*NciTransitionFunc)(
+ NciTransition* transition,
+ void* user_data);
+
+NciTransition*
+nci_transition_ref(
+ NciTransition* transition);
+
+void
+nci_transition_unref(
+ NciTransition* transition);
+
+gboolean
+nci_transition_start(
+ NciTransition* self);
+
+void
+nci_transition_finished(
+ NciTransition* self);
+
+void
+nci_transition_handle_ntf(
+ NciTransition* transition,
+ guint8 gid,
+ guint8 oid,
+ const GUtilData* payload);
+
+/* Specific transitions */
+
+NciTransition*
+nci_transition_reset_new(
+ NciSm* sm);
+
+NciTransition*
+nci_transition_idle_to_discovery_new(
+ NciSm* sm);
+
+NciTransition*
+nci_transition_deactivate_to_idle_new(
+ NciSm* sm);
+
+NciTransition*
+nci_transition_poll_active_to_discovery_new(
+ NciSm* sm);
+
+NciTransition*
+nci_transition_poll_active_to_idle_new(
+ NciSm* sm);
+
+#endif /* NCI_TRANSITION_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_transition_deactivate_to_idle.c
^
|
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "nci_transition.h"
+#include "nci_transition_impl.h"
+#include "nci_sm.h"
+#include "nci_log.h"
+
+/*==========================================================================*
+ *
+ * 5.2.2 State RFST_DISCOVERY
+ * 5.2.3 State RFST_W4_ALL_DISCOVERIES
+ * 5.2.4 State RFST_W4_HOST_SELECT
+ *
+ * ...
+ *
+ * If the DH sends RF_DEACTIVATE_CMD, the NFCC SHALL ignore the Deactivation
+ * Type parameter, stop the RF Discovery Process, and send RF_DEACTIVATE_RSP.
+ * The state will then change to RFST_IDLE.
+ *
+ *==========================================================================*/
+
+typedef NciTransition NciTransitionDeactivateToIdle;
+typedef NciTransitionClass NciTransitionDeactivateToIdleClass;
+
+G_DEFINE_TYPE(NciTransitionDeactivateToIdle, nci_transition_deactivate_to_idle,
+ NCI_TYPE_TRANSITION)
+#define THIS_TYPE (nci_transition_deactivate_to_idle_get_type())
+#define PARENT_CLASS (nci_transition_deactivate_to_idle_parent_class)
+
+/*==========================================================================*
+ * Implementation
+ *==========================================================================*/
+
+static
+void
+nci_transition_deactivate_to_idle_rsp(
+ NCI_REQUEST_STATUS status,
+ const GUtilData* payload,
+ NciTransition* self)
+{
+ if (status == NCI_REQUEST_CANCELLED || !nci_transition_active(self)) {
+ GDEBUG("RF_DEACTIVATE cancelled");
+ } else if (status == NCI_REQUEST_TIMEOUT) {
+ GDEBUG("RF_DEACTIVATE timed out");
+ nci_transition_stall(self, NCI_STALL_ERROR);
+ } else {
+ const guint8* pkt = payload->bytes;
+ const guint len = payload->size;
+
+ /*
+ * Table 62: Control Messages for RF Interface Deactivation
+ *
+ * RF_DEACTIVATE_RSP
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | Status |
+ * +=========================================================+
+ */
+ if (len > 0 && pkt[0] == NCI_STATUS_OK) {
+ GDEBUG("%c RF_DEACTIVATE_RSP ok", DIR_IN);
+ nci_transition_finish(self, NULL);
+ } else {
+ if (len > 0) {
+ GWARN("%c RF_DEACTIVATE_RSP error %u", DIR_IN, pkt[0]);
+ } else {
+ GWARN("%c Broken RF_DEACTIVATE_RSP", DIR_IN);
+ }
+ nci_transition_stall(self, NCI_STALL_ERROR);
+ }
+ }
+}
+
+/*==========================================================================*
+ * Interface
+ *==========================================================================*/
+
+NciTransition*
+nci_transition_deactivate_to_idle_new(
+ NciSm* sm)
+{
+ NciState* dest = nci_sm_get_state(sm, NCI_RFST_IDLE);
+
+ if (dest) {
+ NciTransition* self = g_object_new(THIS_TYPE, NULL);
+
+ nci_transition_init_base(self, sm, dest);
+ return self;
+ }
+ return NULL;
+}
+
+/*==========================================================================*
+ * Methods
+ *==========================================================================*/
+
+static
+gboolean
+nci_transition_deactivate_to_idle_start(
+ NciTransition* self)
+{
+ return nci_transition_deactivate_to_idle(self,
+ nci_transition_deactivate_to_idle_rsp);
+}
+
+/*==========================================================================*
+ * Internals
+ *==========================================================================*/
+
+static
+void
+nci_transition_deactivate_to_idle_init(
+ NciTransitionDeactivateToIdle* self)
+{
+}
+
+static
+void
+nci_transition_deactivate_to_idle_class_init(
+ NciTransitionDeactivateToIdleClass* klass)
+{
+ klass->start = nci_transition_deactivate_to_idle_start;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_transition_idle_to_discovery.c
^
|
@@ -0,0 +1,476 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "nci_transition.h"
+#include "nci_transition_impl.h"
+#include "nci_sm.h"
+#include "nci_log.h"
+
+/*==========================================================================*
+ * NCI_RFST_IDLE -> NCI_RFST_DISCOVERY transition
+ *==========================================================================*/
+
+typedef NciTransition NciTransitionIdleToDiscovery;
+typedef NciTransitionClass NciTransitionIdleToDiscoveryClass;
+
+G_DEFINE_TYPE(NciTransitionIdleToDiscovery, nci_transition_idle_to_discovery,
+ NCI_TYPE_TRANSITION)
+#define THIS_TYPE (nci_transition_idle_to_discovery_get_type())
+#define PARENT_CLASS (nci_transition_idle_to_discovery_parent_class)
+
+/*==========================================================================*
+ * Implementation
+ *==========================================================================*/
+
+static
+void
+nci_transition_idle_to_discovery_discover_rsp(
+ NCI_REQUEST_STATUS status,
+ const GUtilData* payload,
+ NciTransition* self)
+{
+ if (status == NCI_REQUEST_CANCELLED || !nci_transition_active(self)) {
+ GDEBUG("RF_DISCOVER_MAP cancelled");
+ } else if (status == NCI_REQUEST_TIMEOUT) {
+ GDEBUG("RF_DISCOVER_MAP timed out");
+ nci_transition_stall(self, NCI_STALL_ERROR);
+ } else {
+ const guint8* pkt = payload->bytes;
+ const guint len = payload->size;
+
+ /*
+ * Table 52: Control Messages to Start Discovery
+ *
+ * RF_DISCOVER_RSP
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | Status |
+ * +=========================================================+
+ */
+ if (len > 0 && pkt[0] == NCI_STATUS_OK) {
+ GDEBUG("%c RF_DISCOVER_RSP ok", DIR_IN);
+ nci_transition_finish(self, NULL);
+ } else {
+ if (len > 0) {
+ GWARN("%c RF_DISCOVER_RSP error %u", DIR_IN, pkt[0]);
+ } else {
+ GWARN("%c Broken RF_DISCOVER_RSP", DIR_IN);
+ }
+ nci_transition_stall(self, NCI_STALL_ERROR);
+ }
+ }
+}
+
+static
+void
+nci_transition_idle_to_discovery_discover(
+ NciTransition* self)
+{
+ /*
+ * Table 52: Control Messages to Start Discovery
+ *
+ * RF_DISCOVER_CMD
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | Number of Configurations |
+ * | 1 | 2*n | Configurations: |
+ * | | +-----------------------------------------+
+ * | | | 0 | RF Technology and Mode |
+ * | | | 1 | Frequency (1 = every period) |
+ * +=========================================================+
+ */
+ static const guint8 cmd[] = {
+ 0x04,
+ NCI_MODE_PASSIVE_POLL_A, 1,
+ NCI_MODE_PASSIVE_POLL_B, 1,
+ NCI_MODE_PASSIVE_POLL_F, 1,
+ NCI_MODE_PASSIVE_POLL_15693, 1
+ };
+
+ GDEBUG("%c RF_DISCOVER_CMD", DIR_OUT);
+ nci_transition_send_command_static(self, NCI_GID_RF, NCI_OID_RF_DISCOVER,
+ cmd, sizeof(cmd), nci_transition_idle_to_discovery_discover_rsp);
+}
+
+static
+void
+nci_transition_idle_to_discover_map_rsp(
+ NCI_REQUEST_STATUS status,
+ const GUtilData* payload,
+ NciTransition* self)
+{
+ if (status == NCI_REQUEST_CANCELLED || !nci_transition_active(self)) {
+ GDEBUG("RF_DISCOVER_MAP cancelled");
+ } else if (status == NCI_REQUEST_TIMEOUT) {
+ GDEBUG("RF_DISCOVER_MAP timed out");
+ nci_transition_stall(self, NCI_STALL_ERROR);
+ } else {
+ const guint8* pkt = payload->bytes;
+ const guint len = payload->size;
+
+ /*
+ * Table 42: Control Messages for RF Interface Mapping Configuration
+ *
+ * RF_DISCOVER_MAP_RSP
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | Status |
+ * +=========================================================+
+ */
+ if (len > 0 && pkt[0] == NCI_STATUS_OK) {
+ GDEBUG("%c RF_DISCOVER_MAP_RSP ok", DIR_IN);
+ nci_transition_idle_to_discovery_discover(self);
+ } else {
+ if (len > 0) {
+ GWARN("%c RF_DISCOVER_MAP_RSP error %u", DIR_IN, pkt[0]);
+ } else {
+ GWARN("%c Broken RF_DISCOVER_MAP_RSP", DIR_IN);
+ }
+ nci_transition_stall(self, NCI_STALL_ERROR);
+ }
+ }
+}
+
+static
+gboolean
+nci_transition_idle_to_discover_map(
+ NciTransition* self)
+{
+ /*
+ * Table 42: Control Messages for RF Interface Mapping Configuration
+ *
+ * RF_DISCOVER_MAP_CMD
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | Number of Mapping Configurations (n) |
+ * | 1 | 3*n | Mapping Configurations: |
+ * | | +-----------------------------------------+
+ * | | | 0 | RF Protocol |
+ * | | | 1 | Mode |
+ * | | | 2 | RF Interface |
+ * +=========================================================+
+ */
+ static const guint8 cmd[] = {
+ 0x05,
+
+ NCI_PROTOCOL_T1T,
+ NCI_DISCOVER_MAP_MODE_POLL,
+ NCI_RF_INTERFACE_FRAME,
+
+ NCI_PROTOCOL_T2T,
+ NCI_DISCOVER_MAP_MODE_POLL,
+ NCI_RF_INTERFACE_FRAME,
+
+ NCI_PROTOCOL_T3T,
+ NCI_DISCOVER_MAP_MODE_POLL,
+ NCI_RF_INTERFACE_FRAME,
+
+ NCI_PROTOCOL_ISO_DEP,
+ NCI_DISCOVER_MAP_MODE_POLL,
+ NCI_RF_INTERFACE_ISO_DEP,
+
+ NCI_PROTOCOL_NFC_DEP,
+ NCI_DISCOVER_MAP_MODE_POLL,
+ NCI_RF_INTERFACE_NFC_DEP
+ };
+
+ GDEBUG("%c RF_DISCOVER_MAP_CMD", DIR_OUT);
+ return nci_transition_send_command_static(self, NCI_GID_RF,
+ NCI_OID_RF_DISCOVER_MAP, cmd, sizeof(cmd),
+ nci_transition_idle_to_discover_map_rsp);
+}
+
+/*
+ * Table 44: Control Messages to Configure Listen Mode Routing
+ *
+ * RF_SET_LISTEN_MODE_ROUTING_CMD
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | More | 0 | Last Message |
+ * | | | | 1 | More Message(s) to follow |
+ * | | +-----------------------------------------+
+ * | 1 | 1 | The number of Routing Entries (n) |
+ * | 2 | n*x | Routing Entries |
+ * +=========================================================+
+ */
+static
+inline
+gboolean
+nci_transition_idle_to_discovery_set_routing(
+ NciTransition* self,
+ const void* cmd,
+ gsize cmd_len,
+ NciTransitionResponseFunc resp)
+{
+ return nci_transition_send_command_static(self, NCI_GID_RF,
+ NCI_OID_RF_SET_LISTEN_MODE_ROUTING, cmd, cmd_len, resp);
+}
+
+static
+void
+nci_transition_idle_to_discovery_set_technology_routing_rsp(
+ NCI_REQUEST_STATUS status,
+ const GUtilData* payload,
+ NciTransition* self)
+{
+ if (status == NCI_REQUEST_CANCELLED || !nci_transition_active(self)) {
+ GDEBUG("RF_SET_LISTEN_MODE_ROUTING (Technology) cancelled");
+ } else if (status == NCI_REQUEST_TIMEOUT) {
+ GDEBUG("RF_SET_LISTEN_MODE_ROUTING (Technology) timed out");
+ nci_transition_stall(self, NCI_STALL_ERROR);
+ } else {
+ const guint8* pkt = payload->bytes;
+ const guint len = payload->size;
+
+ if (len > 0 && pkt[0] == NCI_STATUS_OK) {
+ GDEBUG("%c RF_SET_LISTEN_MODE_ROUTING_RSP (Technology) ok", DIR_IN);
+ } else if (len > 0) {
+ GDEBUG("%c RF_SET_LISTEN_MODE_ROUTING_RSP (Technology) error %u",
+ DIR_IN, pkt[0]);
+ } else {
+ GDEBUG("%c Broken RF_SET_LISTEN_MODE_ROUTING_RSP (Technology)",
+ DIR_IN);
+ }
+
+ /* Ignore errors */
+ nci_transition_idle_to_discover_map(self);
+ }
+}
+
+static
+gboolean
+nci_transition_idle_to_discovery_set_technology_routing(
+ NciTransition* self)
+{
+ static const guint8 cmd[] = {
+ 0x00, /* Last message */
+ 0x04, /* Number of Routing Entries */
+
+ NCI_ROUTING_ENTRY_TYPE_TECHNOLOGY,
+ 3,
+ NCI_NFCEE_ID_DH,
+ NCI_ROUTING_ENTRY_POWER_ON,
+ NCI_RF_TECHNOLOGY_A,
+
+ NCI_ROUTING_ENTRY_TYPE_TECHNOLOGY,
+ 3,
+ NCI_NFCEE_ID_DH,
+ NCI_ROUTING_ENTRY_POWER_ON,
+ NCI_RF_TECHNOLOGY_B,
+
+ NCI_ROUTING_ENTRY_TYPE_TECHNOLOGY,
+ 3,
+ NCI_NFCEE_ID_DH,
+ NCI_ROUTING_ENTRY_POWER_ON,
+ NCI_RF_TECHNOLOGY_F,
+
+ NCI_ROUTING_ENTRY_TYPE_TECHNOLOGY,
+ 3,
+ NCI_NFCEE_ID_DH,
+ NCI_ROUTING_ENTRY_POWER_ON,
+ NCI_RF_TECHNOLOGY_15693,
+ };
+
+ GDEBUG("%c RF_SET_LISTEN_MODE_ROUTING_CMD (Technology)", DIR_OUT);
+ return nci_transition_idle_to_discovery_set_routing(self, cmd, sizeof(cmd),
+ nci_transition_idle_to_discovery_set_technology_routing_rsp);
+}
+
+static
+void
+nci_transition_idle_to_discovery_set_protocol_routing_rsp(
+ NCI_REQUEST_STATUS status,
+ const GUtilData* payload,
+ NciTransition* self)
+{
+ NciSm* sm = nci_transition_sm(self);
+
+ if (status == NCI_REQUEST_CANCELLED || !nci_transition_active(self)) {
+ GDEBUG("RF_SET_LISTEN_MODE_ROUTING (Protocol) cancelled");
+ } else if (status == NCI_REQUEST_TIMEOUT) {
+ GDEBUG("RF_SET_LISTEN_MODE_ROUTING (Protocol) timed out");
+ nci_sm_stall(sm, NCI_STALL_ERROR);
+ } else if (sm) {
+ const guint8* pkt = payload->bytes;
+ const guint len = payload->size;
+
+ if (len > 0 && pkt[0] == NCI_STATUS_OK) {
+ GDEBUG("%c RF_SET_LISTEN_MODE_ROUTING_RSP (Protocol) ok", DIR_IN);
+ nci_transition_idle_to_discover_map(self);
+ } else {
+ if (len > 0) {
+ GDEBUG("%c RF_SET_LISTEN_MODE_ROUTING_RSP (Protocol) error %u",
+ DIR_IN, pkt[0]);
+ } else {
+ GDEBUG("%c Broken RF_SET_LISTEN_MODE_ROUTING_RSP (Protocol)",
+ DIR_IN);
+ }
+ if (sm->nfcc_routing & NCI_NFCC_ROUTING_TECHNOLOGY_BASED) {
+ nci_transition_idle_to_discovery_set_technology_routing(self);
+ } else {
+ nci_transition_idle_to_discover_map(self);
+ }
+ }
+ }
+}
+
+static
+gboolean
+nci_transition_idle_to_discovery_set_protocol_routing(
+ NciTransition* self)
+{
+ static const guint8 cmd[] = {
+ 0x00, /* Last message */
+ 0x05, /* Number of Routing Entries */
+
+ NCI_ROUTING_ENTRY_TYPE_PROTOCOL,
+ 3,
+ NCI_NFCEE_ID_DH,
+ NCI_ROUTING_ENTRY_POWER_ON,
+ NCI_PROTOCOL_T1T,
+
+ NCI_ROUTING_ENTRY_TYPE_PROTOCOL,
+ 3,
+ NCI_NFCEE_ID_DH,
+ NCI_ROUTING_ENTRY_POWER_ON,
+ NCI_PROTOCOL_T2T,
+
+ NCI_ROUTING_ENTRY_TYPE_PROTOCOL,
+ 3,
+ NCI_NFCEE_ID_DH,
+ NCI_ROUTING_ENTRY_POWER_ON,
+ NCI_PROTOCOL_T3T,
+
+ NCI_ROUTING_ENTRY_TYPE_PROTOCOL,
+ 3,
+ NCI_NFCEE_ID_DH,
+ NCI_ROUTING_ENTRY_POWER_ON,
+ NCI_PROTOCOL_ISO_DEP,
+
+ NCI_ROUTING_ENTRY_TYPE_PROTOCOL,
+ 3,
+ NCI_NFCEE_ID_DH,
+ NCI_ROUTING_ENTRY_POWER_ON,
+ NCI_PROTOCOL_NFC_DEP,
+ };
+
+ GDEBUG("%c RF_SET_LISTEN_MODE_ROUTING_CMD (Protocol)", DIR_OUT);
+ return nci_transition_idle_to_discovery_set_routing(self, cmd, sizeof(cmd),
+ nci_transition_idle_to_discovery_set_protocol_routing_rsp);
+}
+
+/*==========================================================================*
+ * Interface
+ *==========================================================================*/
+
+NciTransition*
+nci_transition_idle_to_discovery_new(
+ NciSm* sm)
+{
+ NciState* dest = nci_sm_get_state(sm, NCI_RFST_DISCOVERY);
+
+ if (dest) {
+ NciTransition* self = g_object_new(THIS_TYPE, NULL);
+
+ nci_transition_init_base(self, sm, dest);
+ return self;
+ }
+ return NULL;
+}
+
+/*==========================================================================*
+ * Methods
+ *==========================================================================*/
+
+static
+gboolean
+nci_transition_idle_to_discovery_start(
+ NciTransition* self)
+{
+ NciSm* sm = nci_transition_sm(self);
+
+ if (sm) {
+ gboolean (*fn)(NciTransition*) = nci_transition_idle_to_discover_map;
+ /*
+ * Some controllers seem to require RF_SET_LISTEN_MODE_ROUTING,
+ * some don't support it at all. Let's give it a try (provided
+ * that controller indicated support for protocol based routing
+ * in CORE_INIT_RSP) and ignore any errors.
+ */
+ if (sm->version > NCI_INTERFACE_VERSION_1) {
+ if (sm->nfcc_routing & NCI_NFCC_ROUTING_PROTOCOL_BASED) {
+ fn = nci_transition_idle_to_discovery_set_protocol_routing;
+ } else if (sm->nfcc_routing & NCI_NFCC_ROUTING_TECHNOLOGY_BASED) {
+ fn = nci_transition_idle_to_discovery_set_technology_routing;
+ }
+ }
+ return fn(self);
+ }
+ return FALSE;
+}
+
+/*==========================================================================*
+ * Internals
+ *==========================================================================*/
+
+static
+void
+nci_transition_idle_to_discovery_init(
+ NciTransitionIdleToDiscovery* self)
+{
+}
+
+static
+void
+nci_transition_idle_to_discovery_class_init(
+ NciTransitionIdleToDiscoveryClass* klass)
+{
+ klass->start = nci_transition_idle_to_discovery_start;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_transition_impl.h
^
|
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NCI_TRANSITION_IMPL_H
+#define NCI_TRANSITION_IMPL_H
+
+#include "nci_transition.h"
+
+/* Internal API for use by NciTransition implemenations */
+
+typedef struct nci_transition_class {
+ GObjectClass parent;
+ gboolean (*start)(NciTransition* self);
+ void (*finished)(NciTransition* self);
+ void (*handle_ntf)(NciTransition* self, guint8 gid, guint8 oid,
+ const GUtilData* payload);
+} NciTransitionClass;
+
+#define NCI_TRANSITION_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), \
+ NCI_TYPE_TRANSITION, NciTransitionClass)
+
+typedef
+void
+(*NciTransitionResponseFunc)(
+ NCI_REQUEST_STATUS status,
+ const GUtilData* payload,
+ NciTransition* transition);
+
+void
+nci_transition_init_base(
+ NciTransition* self,
+ NciSm* sm,
+ NciState* dest);
+
+NciSm*
+nci_transition_sm(
+ NciTransition* self);
+
+void
+nci_transition_finish(
+ NciTransition* self,
+ void* param);
+
+void
+nci_transition_stall(
+ NciTransition* self,
+ NCI_STALL stall);
+
+gboolean
+nci_transition_active(
+ NciTransition* self);
+
+gboolean
+nci_transition_send_command(
+ NciTransition* self,
+ guint8 gid,
+ guint8 oid,
+ GBytes* payload,
+ NciTransitionResponseFunc resp);
+
+gboolean
+nci_transition_send_command_static(
+ NciTransition* self,
+ guint8 gid,
+ guint8 oid,
+ const void* payload,
+ gsize payload_len,
+ NciTransitionResponseFunc resp);
+
+gboolean
+nci_transition_deactivate_to_idle(
+ NciTransition* self,
+ NciTransitionResponseFunc resp);
+
+gboolean
+nci_transition_deactivate_to_discovery(
+ NciTransition* self,
+ NciTransitionResponseFunc resp);
+
+#endif /* NCI_TRANSITION_IMPL_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_transition_poll_active_to_discovery.c
^
|
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "nci_transition.h"
+#include "nci_transition_impl.h"
+#include "nci_sm.h"
+#include "nci_log.h"
+
+/*==========================================================================*
+ *
+ * 5.2.5 State RFST_POLL_ACTIVE
+ *
+ * ...
+ * If the DH sends RF_DEACTIVATE_CMD (Discovery), the NFCC SHALL send
+ * RF_DEACTIVATE_RSP followed by RF_DEACTIVATE_NTF (Discovery, DH Request)
+ * upon successful deactivation. The state will then change to RFST_DISCOVERY
+ * where the NFCC SHALL either restart or continue the Polling discovery
+ * activity.
+ *
+ *==========================================================================*/
+
+typedef NciTransition NciTransitionPollActiveToDiscovery;
+typedef NciTransitionClass NciTransitionPollActiveToDiscoveryClass;
+
+G_DEFINE_TYPE(NciTransitionPollActiveToDiscovery,
+ nci_transition_poll_active_to_discovery, NCI_TYPE_TRANSITION)
+#define THIS_TYPE (nci_transition_poll_active_to_discovery_get_type())
+#define PARENT_CLASS (nci_transition_poll_active_to_discovery_parent_class)
+
+/*==========================================================================*
+ * Implementation
+ *==========================================================================*/
+
+static
+void
+nci_transition_poll_active_to_discovery_idle_rsp(
+ NCI_REQUEST_STATUS status,
+ const GUtilData* payload,
+ NciTransition* self)
+{
+ if (status == NCI_REQUEST_CANCELLED || !nci_transition_active(self)) {
+ GDEBUG("RF_DEACTIVATE (Idle) cancelled");
+ return;
+ } else if (status == NCI_REQUEST_TIMEOUT) {
+ GDEBUG("RF_DEACTIVATE (Idle) timed out");
+ } else if (status == NCI_REQUEST_SUCCESS) {
+ const guint8* rsp = payload->bytes;
+ const guint len = payload->size;
+
+ if (len == 1 && rsp[0] == NCI_STATUS_OK) {
+ GDEBUG("%c RF_DEACTIVATE_RSP (Idle) ok", DIR_IN);
+ nci_sm_enter_state(nci_transition_sm(self), NCI_RFST_IDLE, NULL);
+ return;
+ } else if (len > 0) {
+ GWARN("%c RF_DEACTIVATE_RSP (Idle) error %u", DIR_IN, rsp[0]);
+ } else {
+ GWARN("%c Broken RF_DEACTIVATE_RSP (Idle)", DIR_IN);
+ }
+ }
+ nci_transition_stall(self, NCI_STALL_ERROR);
+}
+
+static
+void
+nci_transition_poll_active_to_discovery_rsp(
+ NCI_REQUEST_STATUS status,
+ const GUtilData* payload,
+ NciTransition* self)
+{
+ if (status == NCI_REQUEST_CANCELLED || !nci_transition_active(self)) {
+ GDEBUG("RF_DEACTIVATE (Discovery) cancelled");
+ } else if (status == NCI_REQUEST_TIMEOUT) {
+ GDEBUG("RF_DEACTIVATE (Discovery) timed out");
+ nci_transition_stall(self, NCI_STALL_ERROR);
+ } else if (status == NCI_REQUEST_SUCCESS) {
+ const guint8* rsp = payload->bytes;
+ const guint len = payload->size;
+
+ if (len == 1 && rsp[0] == NCI_STATUS_OK) {
+ GDEBUG("%c RF_DEACTIVATE_RSP (Discovery) ok", DIR_IN);
+ /* Wait for RF_DEACTIVATE_NTF */
+ } else {
+ /* Try to deactivate to IDLE */
+ GWARN("RF_DEACTIVATE_CMD (Discovery) failed");
+ nci_transition_deactivate_to_idle(self,
+ nci_transition_poll_active_to_discovery_idle_rsp);
+ }
+ } else {
+ nci_transition_stall(self, NCI_STALL_ERROR);
+ }
+}
+
+/*==========================================================================*
+ * Interface
+ *==========================================================================*/
+
+NciTransition*
+nci_transition_poll_active_to_discovery_new(
+ NciSm* sm)
+{
+ NciState* dest = nci_sm_get_state(sm, NCI_RFST_DISCOVERY);
+
+ if (dest) {
+ NciTransition* self = g_object_new(THIS_TYPE, NULL);
+
+ nci_transition_init_base(self, sm, dest);
+ return self;
+ }
+ return NULL;
+}
+
+/*==========================================================================*
+ * Methods
+ *==========================================================================*/
+
+static
+gboolean
+nci_transition_poll_active_to_discovery_start(
+ NciTransition* self)
+{
+ return nci_transition_deactivate_to_discovery(self,
+ nci_transition_poll_active_to_discovery_rsp);
+}
+
+static
+void
+nci_transition_poll_active_to_discovery_handle_ntf(
+ NciTransition* self,
+ guint8 gid,
+ guint8 oid,
+ const GUtilData* payload)
+{
+ switch (gid) {
+ case NCI_GID_RF:
+ switch (oid) {
+ case NCI_OID_RF_DEACTIVATE:
+ nci_sm_handle_rf_deactivate_ntf(nci_transition_sm(self), payload);
+ return;
+ }
+ break;
+ }
+ NCI_TRANSITION_CLASS(PARENT_CLASS)->handle_ntf(self, gid, oid, payload);
+}
+
+/*==========================================================================*
+ * Internals
+ *==========================================================================*/
+
+static
+void
+nci_transition_poll_active_to_discovery_init(
+ NciTransitionPollActiveToDiscovery* self)
+{
+}
+
+static
+void
+nci_transition_poll_active_to_discovery_class_init(
+ NciTransitionPollActiveToDiscoveryClass* klass)
+{
+ klass->start = nci_transition_poll_active_to_discovery_start;
+ klass->handle_ntf = nci_transition_poll_active_to_discovery_handle_ntf;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_transition_poll_active_to_idle.c
^
|
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "nci_transition.h"
+#include "nci_transition_impl.h"
+#include "nci_sm.h"
+#include "nci_log.h"
+
+/*==========================================================================*
+ *
+ * 5.2.5 State RFST_POLL_ACTIVE
+ *
+ * ...
+ * If the DH sends RF_DEACTIVATE_CMD (Idle Mode), the NFCC SHALL send
+ * RF_DEACTIVATE_RSP followed by RF_DEACTIVATE_NTF (Idle Mode, DH Request)
+ * upon successful deactivation. The state will then change to RFST_IDLE.
+ *
+ *==========================================================================*/
+
+typedef NciTransition NciTransitionPollActiveToIdle;
+typedef NciTransitionClass NciTransitionPollActiveToIdleClass;
+
+G_DEFINE_TYPE(NciTransitionPollActiveToIdle,
+ nci_transition_poll_active_to_idle, NCI_TYPE_TRANSITION)
+#define THIS_TYPE (nci_transition_poll_active_to_idle_get_type())
+#define PARENT_CLASS (nci_transition_poll_active_to_idle_parent_class)
+
+/*==========================================================================*
+ * Implementation
+ *==========================================================================*/
+
+static
+void
+nci_transition_poll_active_to_idle_rsp(
+ NCI_REQUEST_STATUS status,
+ const GUtilData* payload,
+ NciTransition* self)
+{
+ if (status == NCI_REQUEST_CANCELLED || !nci_transition_active(self)) {
+ GDEBUG("RF_DEACTIVATE (Idle) cancelled");
+ } else if (status == NCI_REQUEST_TIMEOUT) {
+ GDEBUG("RF_DEACTIVATE (Idle) timed out");
+ nci_transition_stall(self, NCI_STALL_ERROR);
+ } else if (status == NCI_REQUEST_SUCCESS) {
+ const guint8* rsp = payload->bytes;
+ const guint len = payload->size;
+
+ if (len == 1 && rsp[0] == NCI_STATUS_OK) {
+ GDEBUG("%c RF_DEACTIVATE_RSP (Idle) ok", DIR_IN);
+ /* Wait for RF_DEACTIVATE_NTF */
+ } else {
+ if (len > 0) {
+ GWARN("%c RF_DEACTIVATE_RSP (Idle) error %u", DIR_IN, rsp[0]);
+ } else {
+ GWARN("%c Broken RF_DEACTIVATE_RSP (Idle)", DIR_IN);
+ }
+ nci_transition_stall(self, NCI_STALL_ERROR);
+ }
+ }
+}
+
+/*==========================================================================*
+ * Interface
+ *==========================================================================*/
+
+NciTransition*
+nci_transition_poll_active_to_idle_new(
+ NciSm* sm)
+{
+ NciState* dest = nci_sm_get_state(sm, NCI_RFST_IDLE);
+
+ if (dest) {
+ NciTransition* self = g_object_new(THIS_TYPE, NULL);
+
+ nci_transition_init_base(self, sm, dest);
+ return self;
+ }
+ return NULL;
+}
+
+/*==========================================================================*
+ * Methods
+ *==========================================================================*/
+
+static
+void
+nci_transition_poll_active_to_idle_handle_ntf(
+ NciTransition* self,
+ guint8 gid,
+ guint8 oid,
+ const GUtilData* payload)
+{
+ switch (gid) {
+ case NCI_GID_RF:
+ switch (oid) {
+ case NCI_OID_RF_DEACTIVATE:
+ nci_sm_handle_rf_deactivate_ntf(nci_transition_sm(self), payload);
+ return;
+ }
+ break;
+ }
+ NCI_TRANSITION_CLASS(PARENT_CLASS)->handle_ntf(self, gid, oid, payload);
+}
+
+static
+gboolean
+nci_transition_poll_active_to_idle_start(
+ NciTransition* self)
+{
+ return nci_transition_deactivate_to_idle(self,
+ nci_transition_poll_active_to_idle_rsp);
+}
+
+/*==========================================================================*
+ * Internals
+ *==========================================================================*/
+
+static
+void
+nci_transition_poll_active_to_idle_init(
+ NciTransitionPollActiveToIdle* self)
+{
+}
+
+static
+void
+nci_transition_poll_active_to_idle_class_init(
+ NciTransitionPollActiveToIdleClass* klass)
+{
+ klass->start = nci_transition_poll_active_to_idle_start;
+ klass->handle_ntf = nci_transition_poll_active_to_idle_handle_ntf;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_transition_reset.c
^
|
@@ -0,0 +1,591 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "nci_transition.h"
+#include "nci_transition_impl.h"
+#include "nci_sar.h"
+#include "nci_sm.h"
+#include "nci_log.h"
+
+typedef NciTransition NciTransitionReset;
+typedef NciTransitionClass NciTransitionResetClass;
+
+G_DEFINE_TYPE(NciTransitionReset, nci_transition_reset, NCI_TYPE_TRANSITION)
+#define THIS_TYPE (nci_transition_reset_get_type())
+#define PARENT_CLASS (nci_transition_reset_parent_class)
+
+/*==========================================================================*
+ * Implementation
+ *==========================================================================*/
+
+static
+void
+nci_transition_reset_set_config_rsp(
+ NCI_REQUEST_STATUS status,
+ const GUtilData* payload,
+ NciTransition* self)
+{
+ NciSm* sm = nci_transition_sm(self);
+
+ if (status == NCI_REQUEST_CANCELLED || !nci_transition_active(self)) {
+ GDEBUG("CORE_SET_CONFIG cancelled");
+ return;
+ } else if (status == NCI_REQUEST_TIMEOUT) {
+ GDEBUG("CORE_SET_CONFIG timed out");
+ } else if (sm) {
+ /*
+ * Table 10: Control Messages for Setting Configuration Parameters
+ *
+ * CORE_SET_CONFIG_RSP
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | Status |
+ * | 1 | 1 | The number of invalid Parameters (n) |
+ * | 2 | n | Invalid parameters |
+ * +=========================================================+
+ */
+ if (status == NCI_REQUEST_SUCCESS &&
+ payload->size >= 2 &&
+ payload->bytes[0] == NCI_STATUS_OK) {
+ GDEBUG("%c CORE_SET_CONFIG_RSP ok", DIR_IN);
+ } else {
+ GWARN("CORE_SET_CONFIG_CMD failed (continuing anyway)");
+ }
+ nci_transition_finish(self, NULL);
+ return;
+ }
+ nci_sm_stall(sm, NCI_STALL_ERROR);
+}
+
+static
+void
+nci_transition_reset_set_config(
+ NciTransition* self)
+{
+ /*
+ * Table 10: Control Messages for Setting Configuration Parameters
+ *
+ * CORE_SET_CONFIG_CMD
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | The number of Parameter fields (n) |
+ * | 1 | ... | Parameters * n |
+ * | | +-----------------------------------------+
+ * | | | ID | 1 | The identifier |
+ * | | | Len | 1 | The length of Val (m) |
+ * | | | Val | m | The value of the parameter |
+ * +=========================================================+
+ */
+ static const guint8 cmd[] = {
+ 2,
+ NCI_CONFIG_PA_BAIL_OUT, 0x01, 0x00,
+ NCI_CONFIG_PB_BAIL_OUT, 0x01, 0x00
+ };
+
+ GDEBUG("%c CORE_SET_CONFIG_CMD", DIR_OUT);
+ nci_transition_send_command_static(self,
+ NCI_GID_CORE, NCI_OID_CORE_SET_CONFIG, cmd, sizeof(cmd),
+ nci_transition_reset_set_config_rsp);
+}
+
+static
+void
+nci_transition_reset_get_config_rsp(
+ NCI_REQUEST_STATUS status,
+ const GUtilData* payload,
+ NciTransition* self)
+{
+ NciSm* sm = nci_transition_sm(self);
+
+ if (status == NCI_REQUEST_CANCELLED || !nci_transition_active(self)) {
+ GDEBUG("CORE_GET_CONFIG cancelled");
+ return;
+ } else if (status == NCI_REQUEST_TIMEOUT) {
+ GDEBUG("CORE_GET_CONFIG timed out");
+ } else if (sm) {
+ /*
+ * Table 11: Control Messages for Reading Current Configuration
+ *
+ * CORE_GET_CONFIG_RSP
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | Status |
+ * | 1 | 1 | The number of Parameters (n) |
+ * | 2 | ... | Parameters |
+ * | | +-----------------------------------------+
+ * | | | ID | 1 | The identifier |
+ * | | | Len | 1 | The length of Val (m) |
+ * | | | Val | m | The value of the parameter |
+ * +=========================================================+
+ */
+ if (status == NCI_REQUEST_SUCCESS && payload->size >= 2) {
+ const guint8* pkt = payload->bytes;
+ const guint len = payload->size;
+ const guint n = pkt[1];
+
+ if (pkt[0] == NCI_STATUS_OK) {
+ GDEBUG("%c CORE_GET_CONFIG_RSP ok", DIR_IN);
+ } else if (pkt[0] == NCI_STATUS_INVALID_PARAM && len >= 2 + n*2) {
+#if GUTIL_LOG_DEBUG
+ /*
+ * [NFCForum-TS-NCI-1.0]
+ * 4.3.2 Retrieve the Configuration
+ *
+ * If the DH tries to retrieve any parameter(s) that
+ * are not available in the NFCC, the NFCC SHALL respond
+ * with a CORE_GET_CONFIG_RSP with a Status field of
+ * STATUS_INVALID_PARAM, containing each unavailable
+ * Parameter ID with a Parameter Len field of value zero.
+ * In this case, the CORE_GET_CONFIG_RSP SHALL NOT include
+ * any parameter(s) that are available on the NFCC.
+ */
+ if (GLOG_ENABLED(GLOG_LEVEL_DEBUG)) {
+ GString* buf = g_string_new(NULL);
+ guint i;
+
+ for (i = 0; i < n; i++) {
+ g_string_append_printf(buf, " %02x", pkt[2 + i*2]);
+ }
+ GDEBUG("%c CORE_GET_CONFIG_RSP invalid parameter(s):%s",
+ DIR_IN, buf->str);
+ g_string_free(buf, TRUE);
+ }
+#endif
+ } else {
+ GWARN("CORE_GET_CONFIG_CMD error 0x%02x (continuing anyway)",
+ payload->bytes[0]);
+ }
+ nci_transition_reset_set_config(self);
+ return;
+ } else {
+ GWARN("CORE_GET_CONFIG_CMD failed (continuing anyway)");
+ }
+ }
+ nci_sm_stall(sm, NCI_STALL_ERROR);
+}
+
+static
+void
+nci_transition_reset_get_config(
+ NciTransition* self)
+{
+ /*
+ * Table 11: Control Messages for Reading Current Configuration
+ *
+ * CORE_GET_CONFIG_CMD
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | The number of Parameter ID fields (n) |
+ * | 1 | n | Parameter ID |
+ * +=========================================================+
+ */
+ static const guint8 cmd[] = {
+ 2,
+ NCI_CONFIG_PA_BAIL_OUT,
+ NCI_CONFIG_PB_BAIL_OUT
+ };
+
+ /*
+ * We may want to set some parameters some day but for now let's just
+ * query something and see how it works...
+ */
+ GDEBUG("%c CORE_GET_CONFIG_CMD", DIR_OUT);
+ nci_transition_send_command_static(self,
+ NCI_GID_CORE, NCI_OID_CORE_GET_CONFIG, cmd, sizeof(cmd),
+ nci_transition_reset_get_config_rsp);
+}
+
+static
+void
+nci_transition_reset_init_v1_rsp(
+ NCI_REQUEST_STATUS status,
+ const GUtilData* payload,
+ NciTransition* self)
+{
+ NciSm* sm = nci_transition_sm(self);
+ NciSar* sar = nci_sm_sar(sm);
+
+ if (status == NCI_REQUEST_CANCELLED || !nci_transition_active(self)) {
+ GDEBUG("%c CORE_INIT (v1) cancelled", DIR_IN);
+ } else if (status == NCI_REQUEST_TIMEOUT) {
+ GDEBUG("%c CORE_INIT (v1) timed out", DIR_IN);
+ nci_sm_stall(sm, NCI_STALL_ERROR);
+ } else if (sar && status == NCI_REQUEST_SUCCESS) {
+ const guint8* pkt = payload->bytes;
+ const guint len = payload->size;
+ guint n; /* Number of Supported RF Interfaces */
+
+ /*
+ * NFC Controller Interface (NCI), Version 1.1, Section 4.2
+ *
+ * CORE_INIT_RSP
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | Status |
+ * | 1 | 4 | NFCC Features |
+ * | 5 | 1 | Number of Supported RF Interfaces (n) |
+ * | 6 | n | Supported RF Interfaces |
+ * | 6 + n | 1 | Max Logical Connections |
+ * | 7 + n | 2 | Max Routing Table Size |
+ * | 9 + n | 1 | Max Control Packet Payload Size |
+ * | 10 + n | 2 | Max Size for Large Parameters |
+ * | 12 + n | 1 | Manufacturer ID |
+ * | 13 + n | 4 | Manufacturer Specific Information |
+ * +=========================================================+
+ */
+ if (len >= 17 && pkt[0] == NCI_STATUS_OK &&
+ len == ((n = pkt[5]) + 17)) {
+ const guint8* rf_interfaces = pkt + 6;
+ guint8 max_logical_conns = pkt[6 + n];
+ guint8 max_control_packet = pkt[9 + n];
+
+ if (sm->rf_interfaces) {
+ g_bytes_unref(sm->rf_interfaces);
+ sm->rf_interfaces = NULL;
+ }
+ if (n > 0) {
+ sm->rf_interfaces = g_bytes_new(rf_interfaces, n);
+ }
+
+ sm->nfcc_discovery = pkt[1];
+ sm->nfcc_routing = pkt[2];
+ sm->nfcc_power = pkt[3];
+ sm->max_routing_table_size = ((guint)pkt[8 + n] << 8) + pkt[7 + n];
+
+ GDEBUG("%c CORE_INIT_RSP (v1) ok", DIR_IN);
+ GDEBUG(" Features = %02x %02x %02x %02x",
+ pkt[1], pkt[2], pkt[3], pkt[4]);
+#if GUTIL_LOG_DEBUG
+ if (GLOG_ENABLED(GLOG_LEVEL_DEBUG)) {
+ GString* buf = g_string_new(NULL);
+ guint i;
+
+ for (i = 0; i < n; i++) {
+ g_string_append_printf(buf, " %02x", rf_interfaces[i]);
+ }
+ GDEBUG(" Supported interfaces =%s", buf->str);
+ g_string_free(buf, TRUE);
+ }
+#endif
+ GDEBUG(" Max Logical Connections = %u", max_logical_conns);
+ GDEBUG(" Max Routing Table Size = %u", sm->max_routing_table_size);
+ GDEBUG(" Max Control Packet Size = %u", max_control_packet);
+ GDEBUG(" Manufacturer = 0x%02x", pkt[12 + n]);
+ GDEBUG(" Manufacturer Info = %02x %02x %02x %02x",
+ pkt[13 + n], pkt[14 + n], pkt[15 + n], pkt[16 + n]);
+
+ nci_sar_set_max_logical_connections(sar, max_logical_conns);
+ nci_sar_set_max_control_packet_size(sar, max_control_packet);
+ nci_transition_reset_get_config(self);
+ return;
+ }
+ GWARN("CORE_INIT (v1) failed (or is incomprehensible)");
+ nci_sm_stall(sm, NCI_STALL_ERROR);
+ }
+}
+
+static
+void
+nci_transition_reset_init_v2_rsp(
+ NCI_REQUEST_STATUS status,
+ const GUtilData* payload,
+ NciTransition* self)
+{
+ NciSm* sm = nci_transition_sm(self);
+ NciSar* sar = nci_sm_sar(sm);
+
+ if (status == NCI_REQUEST_CANCELLED || !nci_transition_active(self)) {
+ GDEBUG("CORE_INIT (v2) cancelled");
+ return;
+ } else if (status == NCI_REQUEST_TIMEOUT) {
+ GDEBUG("CORE_INIT (v2) timed out");
+ } else if (sar && status == NCI_REQUEST_SUCCESS) {
+ const guint8* pkt = payload->bytes;
+ const guint len = payload->size;
+ guint n; /* Number of Supported RF Interfaces */
+
+ /*
+ * NFC Controller Interface (NCI), Version 2.0, Section 4.2
+ *
+ * CORE_INIT_RSP
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | Status |
+ * | 1 | 4 | NFCC Features |
+ * | 5 | 1 | Max Logical Connections |
+ * | 6 | 2 | Max Routing Table Size |
+ * | 8 | 1 | Max Control Packet Payload Size |
+ * | 9 | 1 | Max Static HCI Packet Size |
+ * | 10 | 1 | Number of Static HCI Connection Credits |
+ * | 11 | 2 | Max NFC-V RF Frame Size |
+ * | 13 | 1 | Number of Supported RF Interfaces (n) |
+ * | 14 | 2*n | Supported RF Interfaces and Extensions |
+ * +=========================================================+
+ */
+ if (len >= 14 && pkt[0] == NCI_STATUS_OK &&
+ len == (2 * (n = pkt[13]) + 14)) {
+ const guint8* rf_interfaces = pkt + 14;
+ guint8 max_logical_conns = pkt[5];
+ guint8 max_control_packet = pkt[8];
+
+ if (sm->rf_interfaces) {
+ g_bytes_unref(sm->rf_interfaces);
+ sm->rf_interfaces = NULL;
+ }
+ if (n > 0) {
+ sm->rf_interfaces = g_bytes_new(rf_interfaces, n);
+ }
+
+ sm->nfcc_discovery = pkt[1];
+ sm->nfcc_routing = pkt[2];
+ sm->nfcc_power = pkt[3];
+ sm->max_routing_table_size = ((guint)pkt[7] << 8) + pkt[6];
+
+ GDEBUG("%c CORE_INIT_RSP (v2) ok", DIR_IN);
+ GDEBUG(" Features = %02x %02x %02x %02x",
+ pkt[1], pkt[2], pkt[3], pkt[4]);
+#if GUTIL_LOG_DEBUG
+ if (GLOG_ENABLED(GLOG_LEVEL_DEBUG)) {
+ GString* buf = g_string_new(NULL);
+ guint i;
+
+ for (i = 0; i < n; i++) {
+ g_string_append_printf(buf, " %02x", rf_interfaces[2 * i]);
+ }
+ GDEBUG(" Supported interfaces =%s", buf->str);
+ g_string_free(buf, TRUE);
+ }
+#endif
+ GDEBUG(" Max Logical Connections = %u", max_logical_conns);
+ GDEBUG(" Max Routing Table Size = %u", sm->max_routing_table_size);
+ GDEBUG(" Max Control Packet Size = %u", max_control_packet);
+
+ nci_sar_set_max_logical_connections(sar, max_logical_conns);
+ nci_sar_set_max_control_packet_size(sar, max_control_packet);
+ nci_transition_reset_get_config(self);
+ return;
+ }
+ GWARN("CORE_INIT (v1) failed (or is incomprehensible)");
+ }
+ nci_sm_stall(sm, NCI_STALL_ERROR);
+}
+
+static
+void
+nci_transition_reset_rsp(
+ NCI_REQUEST_STATUS status,
+ const GUtilData* payload,
+ NciTransition* self)
+{
+ NciSm* sm = nci_transition_sm(self);
+
+ if (status == NCI_REQUEST_CANCELLED || !nci_transition_active(self)) {
+ GDEBUG("CORE_RESET cancelled");
+ return;
+ } else if (status == NCI_REQUEST_TIMEOUT) {
+ GDEBUG("CORE_RESET timed out");
+ } else if (sm && status == NCI_REQUEST_SUCCESS) {
+ const guint8* pkt = payload->bytes;
+ const guint len = payload->size;
+
+ /*
+ * Table 5: Control Messages to Reset the NFCC
+ *
+ * CORE_RESET_RSP
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | Status |
+ * | 1 | 1 | NCI Version (0x10 == 1.0) |
+ * | 2 | 1 | Configuration Status |
+ * +=========================================================+
+ */
+ if (len == 3) {
+ sm->version = NCI_INTERFACE_VERSION_1;
+ if (pkt[0] == NCI_STATUS_OK) {
+ GDEBUG("%c CORE_RESET_RSP (v1) ok", DIR_IN);
+ GDEBUG("%c CORE_INIT_CMD (v1)", DIR_OUT);
+ nci_transition_send_command(self, NCI_GID_CORE,
+ NCI_OID_CORE_INIT, NULL, nci_transition_reset_init_v1_rsp);
+ return;
+ }
+ GWARN("CORE_RESET_CMD failed");
+ } else if (len == 1) {
+ sm->version = NCI_INTERFACE_VERSION_2;
+ if (pkt[0] == NCI_STATUS_OK) {
+ /* Wait for notification */
+ GDEBUG("%c CORE_RESET_RSP (v2) ok", DIR_IN);
+ return;
+ }
+ GWARN("CORE_RESET_CMD (v2) failed");
+ } else {
+ GWARN("Unexpected CORE_RESET_RSP length %u byte(s)", len);
+ }
+ }
+ nci_sm_stall(sm, NCI_STALL_ERROR);
+}
+
+/*==========================================================================*
+ * Interface
+ *==========================================================================*/
+
+NciTransition*
+nci_transition_reset_new(
+ NciSm* sm)
+{
+ NciState* dest = nci_sm_get_state(sm, NCI_RFST_IDLE);
+
+ if (dest) {
+ NciTransition* self = g_object_new(THIS_TYPE, NULL);
+
+ nci_transition_init_base(self, sm, dest);
+ return self;
+ }
+ return NULL;
+}
+
+/*==========================================================================*
+ * Methods
+ *==========================================================================*/
+
+static
+void
+nci_transition_reset_handle_ntf(
+ NciTransition* self,
+ guint8 gid,
+ guint8 oid,
+ const GUtilData* payload)
+{
+ NciSm* sm = nci_transition_sm(self);
+
+ switch (gid) {
+ case NCI_GID_CORE:
+ switch (oid) {
+ case NCI_OID_CORE_RESET:
+ /* Notification is only expected in NCI 2.x case */
+ if (sm && sm->version == NCI_INTERFACE_VERSION_2) {
+ static const guint8 cmd[] = { 0x00, 0x00 };
+
+ GDEBUG("CORE_RESET_NTF (v2)");
+ GDEBUG("%c CORE_INIT_CMD (v2)", DIR_OUT);
+ nci_transition_send_command_static(self,
+ NCI_GID_CORE, NCI_OID_CORE_INIT, cmd, sizeof(cmd),
+ nci_transition_reset_init_v2_rsp);
+ return;
+ }
+ }
+ break;
+ }
+ NCI_TRANSITION_CLASS(PARENT_CLASS)->handle_ntf(self, gid, oid, payload);
+}
+
+static
+gboolean
+nci_transition_reset_start(
+ NciTransition* self)
+{
+ NciSm* sm = nci_transition_sm(self);
+
+ if (sm) {
+ /*
+ * Table 5: Control Messages to Reset the NFCC
+ *
+ * CORE_RESET_CMD
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | Reset Type | 0 | Keep Configuration |
+ * | | | | 1 | Reset Configuration |
+ * +=========================================================+
+ */
+ static const guint8 cmd[] = { 0x00 /* Keep Configuration */ };
+
+ /* Reset the state */
+ if (sm->rf_interfaces) {
+ g_bytes_unref(sm->rf_interfaces);
+ sm->rf_interfaces = NULL;
+ }
+ sm->max_routing_table_size = 0;
+ sm->version = NCI_INTERFACE_VERSION_UNKNOWN;
+ sm->nfcc_discovery = NCI_NFCC_DISCOVERY_NONE;
+ sm->nfcc_routing = NCI_NFCC_ROUTING_NONE;
+ sm->nfcc_power = NCI_NFCC_POWER_NONE;
+
+ GDEBUG("%c CORE_RESET_CMD", DIR_OUT);
+ return nci_transition_send_command_static(self,
+ NCI_GID_CORE, NCI_OID_CORE_RESET, cmd, sizeof(cmd),
+ nci_transition_reset_rsp);
+ }
+ return FALSE;
+}
+
+/*==========================================================================*
+ * Internals
+ *==========================================================================*/
+
+static
+void
+nci_transition_reset_init(
+ NciTransitionReset* self)
+{
+}
+
+static
+void
+nci_transition_reset_class_init(
+ NciTransitionResetClass* klass)
+{
+ klass->start = nci_transition_reset_start;
+ klass->handle_ntf = nci_transition_reset_handle_ntf;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_types_p.h
^
|
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018-2019 Jolla Ltd.
+ * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NCI_TYPES_PRIVATE_H
+#define NCI_TYPES_PRIVATE_H
+
+#include <nci_types.h>
+
+typedef struct nci_param NciParam;
+typedef struct nci_sar NciSar;
+typedef struct nci_sm NciSm;
+typedef struct nci_transition NciTransition;
+
+typedef enum nci_request_status {
+ NCI_REQUEST_SUCCESS,
+ NCI_REQUEST_TIMEOUT,
+ NCI_REQUEST_CANCELLED
+} NCI_REQUEST_STATUS;
+
+typedef
+void
+(*NciSmResponseFunc)(
+ NCI_REQUEST_STATUS status,
+ const GUtilData* payload,
+ gpointer user_data);
+
+/* Stall modes */
+typedef enum nci_stall {
+ NCI_STALL_STOP,
+ NCI_STALL_ERROR
+} NCI_STALL;
+
+/* Debug log */
+#define DIR_IN '>'
+#define DIR_OUT '<'
+
+/* Message Type (MT) */
+#define NCI_MT_MASK (0xe0)
+#define NCI_MT_DATA_PKT (0x00)
+#define NCI_MT_CMD_PKT (0x20)
+#define NCI_MT_RSP_PKT (0x40)
+#define NCI_MT_NTF_PKT (0x60)
+
+/* Packet Boundary Flag (PBF) */
+#define NCI_PBF (0x10)
+
+#endif /* NCI_TYPES_PRIVATE_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_util.c
^
|
@@ -0,0 +1,540 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "nci_util.h"
+#include "nci_log.h"
+
+#include <gutil_macros.h>
+
+const NciModeParam*
+nci_parse_mode_param(
+ NciModeParam* param,
+ NCI_MODE mode,
+ const guint8* bytes,
+ guint len)
+{
+ switch (mode) {
+ case NCI_MODE_ACTIVE_POLL_A:
+ case NCI_MODE_PASSIVE_POLL_A:
+ /*
+ * NFCForum-TS-NCI-1.0
+ * Table 54: Specific Parameters for NFC-A Poll Mode
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 2 | SENS_RES Response |
+ * | 2 | 1 | Length of NFCID1 Parameter (n) |
+ * | 3 | n | NFCID1 (0, 4, 7, or 10 Octets) |
+ * | 3 + n | 1 | SEL_RES Response Length (m) |
+ * | 4 + n | m | SEL_RES Response (0 or 1 Octet) |
+ * +=========================================================+
+ */
+ if (len >= 4) {
+ NciModeParamPollA* ppa = ¶m->poll_a;
+
+ memset(ppa, 0, sizeof(*ppa));
+ ppa->sens_res[0] = bytes[0];
+ ppa->sens_res[1] = bytes[1];
+ ppa->nfcid1_len = bytes[2];
+ if (ppa->nfcid1_len <= sizeof(ppa->nfcid1) &&
+ len >= ppa->nfcid1_len + 4 &&
+ len >= ppa->nfcid1_len + 4 +
+ bytes[ppa->nfcid1_len + 3]) {
+ memcpy(ppa->nfcid1, bytes + 3, ppa->nfcid1_len);
+ ppa->sel_res_len = bytes[ppa->nfcid1_len + 3];
+ if (ppa->sel_res_len) {
+ ppa->sel_res = bytes[ppa->nfcid1_len + 4];
+ }
+#if GUTIL_LOG_DEBUG
+ if (GLOG_ENABLED(GLOG_LEVEL_DEBUG)) {
+ GString* buf = g_string_new(NULL);
+ guint i;
+
+ for (i = 0; i < ppa->nfcid1_len; i++) {
+ g_string_append_printf(buf, " %02x", ppa->nfcid1[i]);
+ }
+ GDEBUG("NFC-A");
+ GDEBUG(" PollA.sel_res = 0x%02x", ppa->sel_res);
+ GDEBUG(" PollA.nfcid1 =%s", buf->str);
+ g_string_free(buf, TRUE);
+ }
+#endif
+ return param;
+ }
+ }
+ GDEBUG("Failed to parse parameters for NFC-A poll mode");
+ return NULL;
+ case NCI_MODE_PASSIVE_POLL_B:
+ /*
+ * NFCForum-TS-NCI-1.0
+ * Table 56: Specific Parameters for NFC-B Poll Mode
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | SENSB_RES Response Length n (11 or 12) |
+ * | 1 | n | Bytes 2-12 or 13 or SENSB_RES Response |
+ * +=========================================================+
+ *
+ * NFCForum-TS-DigitalProtocol-1.0
+ * Table 25: SENSB_RES Format
+ *
+ * +=========================================================+
+ * | Byte 1 | Byte 2-5 | Byte 6-9 | Byte 10-12 or 13 |
+ * +=========================================================+
+ * | 50h | NFCID0 | Application Data | Protocol Info |
+ * +=========================================================+
+ *
+ * Table 27: Protocol Info Format
+ *
+ * +=========================================================+
+ * | Byte 1 | 8 bits | Bit Rate Capability |
+ * +--------+--------+---------------------------------------+
+ * | Byte 2 | 4 bits | FSCI |
+ * | | 4 bits | Protocol_Type |
+ * +--------+--------+---------------------------------------+
+ * | Byte 3 | 4 bits | FWI |
+ * | | 2 bits | ADC |
+ * | | 2 bits | FO |
+ * +-------------------optional -----------------------------+
+ * | Byte 4 | 4 bits | SFGI |
+ * | | 4 bits | RFU |
+ * +=========================================================+
+ *
+ * Table 29: FSCI to FSC Conversion
+ * +=========================================================+
+ * | FSCI | 0h 1h 2h 3h 4h 5h 6h 7h 8h 9h-Fh |
+ * |-------------+-------------------------------------------+
+ * | FSC (bytes) | 16 24 32 40 48 64 96 128 256 RFU |
+ * +=========================================================+
+ */
+ if (len >= 1 && bytes[0] >= 11) {
+ NciModeParamPollB* ppb = ¶m->poll_b;
+ const guint fsci = (bytes[10] >> 4);
+ static const guint fsc_table[] = {
+ 16, 24, 32, 40, 48, 64, 96, 128, 256
+ };
+
+ memset(ppb, 0, sizeof(*ppb));
+ memcpy(ppb->nfcid0, bytes + 1, 4);
+ ppb->fsc = (fsci < G_N_ELEMENTS(fsc_table)) ?
+ fsc_table[fsci] :
+ fsc_table[G_N_ELEMENTS(fsc_table) - 1];
+
+ GDEBUG("NFC-B");
+ GDEBUG(" PollB.fsc = %u", ppb->fsc);
+ GDEBUG(" PollB.nfcid0 = %02x %02x %02x %02x", ppb->nfcid0[0],
+ ppb->nfcid0[1], ppb->nfcid0[2], ppb->nfcid0[3]);
+ return param;
+ }
+ GDEBUG("Failed to parse parameters for NFC-B poll mode");
+ return NULL;
+ default:
+ GDEBUG("Unhandled activation mode %d", mode);
+ return NULL;
+ }
+}
+
+gboolean
+nci_parse_discover_ntf(
+ NciDiscoveryNtf* ntf,
+ NciModeParam* param,
+ const guint8* pkt,
+ guint len)
+{
+ /*
+ * NFCForum-TS-NCI-1.0
+ * Table 52: Control Messages to Start Discovery
+ *
+ * RF_DISCOVER_NTF
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | RF Discovery ID |
+ * | 1 | 1 | RF Protocol |
+ * | 2 | 1 | Activation RF Technology and Mode |
+ * | 3 | 1 | Length of RF Technology Parameters (n) |
+ * | 4 | n | RF Technology Specific Parameters |
+ * | 4 + n | 1 | Notification Type |
+ * | | |-----------------------------------------|
+ * | | | 0 | Last Notification |
+ * | | | 1 | Last Notification (limit reached) |
+ * | | | 2 | More Notification to follow |
+ * +=========================================================+
+ */
+ if (len >= 5) {
+ const guint n = pkt[3];
+
+ if (len >= 5 + n) {
+ ntf->discovery_id = pkt[0];
+ ntf->protocol = pkt[1];
+ ntf->mode = pkt[2];
+ ntf->param_len = n;
+ ntf->param_bytes = n ? (pkt + 4) : NULL;
+ ntf->last = (pkt[4 + n] != 2 /* More to follow */);
+
+#if GUTIL_LOG_DEBUG
+ GDEBUG("RF_DISCOVER_NTF%s", ntf->last ? " (Last)" : "");
+ GDEBUG(" RF Discovery ID = 0x%02x", ntf->discovery_id);
+ GDEBUG(" RF Protocol = 0x%02x", ntf->protocol);
+ GDEBUG(" Activation RF Mode = 0x%02x", ntf->mode);
+ if (n && GLOG_ENABLED(GLOG_LEVEL_DEBUG)) {
+ const guint8* bytes = ntf->param_bytes;
+ GString* buf = g_string_new(NULL);
+ guint i;
+
+ for (i = 0; i < n; i++) {
+ g_string_append_printf(buf, " %02x", bytes[i]);
+ }
+ GDEBUG(" RF Tech Parameters =%s", buf->str);
+ g_string_free(buf, TRUE);
+ }
+#endif /* GUTIL_LOG_DEBUG */
+
+ if (ntf->param_bytes && param) {
+ ntf->param = nci_parse_mode_param(param, ntf->mode,
+ ntf->param_bytes, n);
+ } else {
+ ntf->param = NULL;
+ }
+ return TRUE;
+ }
+ }
+ GDEBUG("Failed to parse RF_DISCOVER_NTF");
+ return FALSE;
+}
+
+static
+gboolean
+nci_parse_iso_dep_poll_a_param(
+ NciActivationParamIsoDepPollA* param,
+ const guint8* bytes,
+ guint len)
+{
+ /* Answer To Select */
+ const guint8 ats_len = bytes[0];
+
+ /*
+ * NFCForum-TS-NCI-1.0
+ * Table 76: Activation Parameters for NFC-A/ISO-DEP Poll Mode
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | RATS Response Length (n) |
+ * | 1 | n | RATS Response starting from Byte 2 |
+ * +=========================================================+
+ */
+ if (ats_len >= 1 && len >= ats_len + 1) {
+ const guint8* ats = bytes + 1;
+ const guint8* ats_end = ats + ats_len;
+ const guint8* ats_ptr = ats;
+ const guint8 t0 = *ats_ptr++;
+
+#define NFC_T4A_ATS_T0_A (0x10) /* TA is transmitted */
+#define NFC_T4A_ATS_T0_B (0x20) /* TB is transmitted */
+#define NFC_T4A_ATS_T0_C (0x30) /* TC is transmitted */
+#define NFC_T4A_ATS_T0_FSCI_MASK (0x0f) /* FSCI mask */
+
+ /* Skip TA, TB and TC if they are present */
+ if (t0 & NFC_T4A_ATS_T0_A) ats_ptr++;
+ if (t0 & NFC_T4A_ATS_T0_B) ats_ptr++;
+ if (t0 & NFC_T4A_ATS_T0_C) ats_ptr++;
+ if (ats_ptr <= ats_end) {
+ /* NFCForum-TS-DigitalProtocol-1.01
+ * Table 66: FSCI to FSC Conversion */
+ const guint8 fsci = (t0 & NFC_T4A_ATS_T0_FSCI_MASK);
+ static const guint fsc_table[] = {
+ 16, 24, 32, 40, 48, 64, 96, 128, 256
+ };
+
+ param->fsc = (fsci < G_N_ELEMENTS(fsc_table)) ?
+ fsc_table[fsci] :
+ fsc_table[G_N_ELEMENTS(fsc_table) - 1];
+ if ((param->t1.size = ats_end - ats_ptr) > 0) {
+ param->t1.bytes = ats_ptr;
+ }
+#if GUTIL_LOG_DEBUG
+ if (GLOG_ENABLED(GLOG_LEVEL_DEBUG)) {
+ GDEBUG("ISO-DEP");
+ GDEBUG(" FSC = %u", param->fsc);
+ if (param->t1.bytes) {
+ GString* buf = g_string_new(NULL);
+ guint i;
+
+ for (i = 0; i < param->t1.size; i++) {
+ g_string_append_printf(buf, " %02x",
+ param->t1.bytes[i]);
+ }
+ GDEBUG(" T1 =%s", buf->str);
+ g_string_free(buf, TRUE);
+ }
+ }
+#endif
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static
+const NciActivationParam*
+nci_parse_activation_param(
+ NciActivationParam* param,
+ NCI_RF_INTERFACE intf,
+ NCI_MODE mode,
+ const guint8* bytes,
+ guint len)
+{
+ switch (intf) {
+ case NCI_RF_INTERFACE_ISO_DEP:
+ switch (mode) {
+ case NCI_MODE_PASSIVE_POLL_A:
+ case NCI_MODE_ACTIVE_POLL_A:
+ if (nci_parse_iso_dep_poll_a_param(¶m->iso_dep_poll_a,
+ bytes, len)) {
+ return param;
+ }
+ GDEBUG("Failed to parse parameters for NFC-A/ISO-DEP poll mode");
+ break;
+ case NCI_MODE_PASSIVE_POLL_B:
+ case NCI_MODE_PASSIVE_POLL_F:
+ case NCI_MODE_ACTIVE_POLL_F:
+ case NCI_MODE_PASSIVE_POLL_15693:
+ case NCI_MODE_PASSIVE_LISTEN_A:
+ case NCI_MODE_PASSIVE_LISTEN_B:
+ case NCI_MODE_PASSIVE_LISTEN_F:
+ case NCI_MODE_ACTIVE_LISTEN_A:
+ case NCI_MODE_ACTIVE_LISTEN_F:
+ case NCI_MODE_PASSIVE_LISTEN_15693:
+ break;
+ }
+ break;
+ case NCI_RF_INTERFACE_FRAME:
+ /* There are no Activation Parameters for Frame RF interface */
+ break;
+ case NCI_RF_INTERFACE_NFCEE_DIRECT:
+ case NCI_RF_INTERFACE_NFC_DEP:
+ GDEBUG("Unhandled interface type");
+ break;
+ }
+ return NULL;
+}
+
+gboolean
+nci_parse_intf_activated_ntf(
+ NciIntfActivationNtf* ntf,
+ NciModeParam* mode_param,
+ NciActivationParam* activation_param,
+ const guint8* pkt,
+ guint len)
+{
+ /*
+ * NFCForum-TS-NCI-1.0
+ * Table 61: Notification for RF Interface activation
+ *
+ * RF_INTF_ACTIVATED_NTF
+ *
+ * +=========================================================+
+ * | Offset | Size | Description |
+ * +=========================================================+
+ * | 0 | 1 | RF Discovery ID |
+ * | 1 | 1 | RF Interface |
+ * | 2 | 1 | RF Protocol |
+ * | 3 | 1 | Activation RF Technology and Mode |
+ * | 4 | 1 | Max Data Packet Payload Size |
+ * | 5 | 1 | Initial Number of Credits |
+ * | 6 | 1 | Length of RF Technology Parameters (n) |
+ * | 7 | n | RF Technology Specific Parameters |
+ * | 7 + n | 1 | Data Exchange RF Technology and Mode |
+ * | 8 + n | 1 | Data Exchange Transmit Bit Rate |
+ * | 9 + n | 1 | Data Exchange Receive Bit Rate |
+ * | 10 + n | 1 | Length of Activation Parameters (m) |
+ * | 11 + n | m | Activation Parameters |
+ * +=========================================================+
+ */
+
+ memset(ntf, 0, sizeof(*ntf));
+ if (len > 6) {
+ const guint n = pkt[6];
+ const guint m = (len > (10 + n)) ? pkt[10 + n] : 0;
+
+ if (len >= 11 + n + m) {
+ const guint8* act_param_bytes = m ? (pkt + (11 + n)) : NULL;
+
+ ntf->discovery_id = pkt[0];
+ ntf->rf_intf = pkt[1];
+ ntf->protocol = pkt[2];
+ ntf->mode = pkt[3];
+ ntf->max_data_packet_size = pkt[4];
+ ntf->num_credits = pkt[5];
+ ntf->mode_param_len = n;
+ ntf->mode_param_bytes = n ? (pkt + 7) : NULL;
+ ntf->data_exchange_mode = pkt[7 + n];
+ ntf->transmit_rate = pkt[8 + n];
+ ntf->receive_rate = pkt[9 + n];
+
+#if GUTIL_LOG_DEBUG
+ GDEBUG("RF_INTF_ACTIVATED_NTF");
+ GDEBUG(" RF Discovery ID = 0x%02x", ntf->discovery_id);
+ GDEBUG(" RF Interface = 0x%02x", ntf->rf_intf);
+ if (ntf->rf_intf != NCI_RF_INTERFACE_NFCEE_DIRECT) {
+ GDEBUG(" RF Protocol = 0x%02x", ntf->protocol);
+ GDEBUG(" Activation RF Mode = 0x%02x", ntf->mode);
+ GDEBUG(" Max Data Packet Size = %u",
+ ntf->max_data_packet_size);
+ GDEBUG(" Initial Credits = %u", ntf->num_credits);
+ if (n || m) {
+ if (GLOG_ENABLED(GLOG_LEVEL_DEBUG)) {
+ GString* buf = g_string_new(NULL);
+ guint i;
+
+ if (n) {
+ const guint8* bytes = ntf->mode_param_bytes;
+
+ for (i = 0; i < n; i++) {
+ g_string_append_printf(buf, " %02x", bytes[i]);
+ }
+ GDEBUG(" RF Tech Parameters =%s", buf->str);
+ }
+ GDEBUG(" Data Exchange RF Tech = 0x%02x",
+ ntf->data_exchange_mode);
+ if (m) {
+ g_string_set_size(buf, 0);
+ for (i = 0; i < m; i++) {
+ g_string_append_printf(buf, " %02x",
+ act_param_bytes[i]);
+ }
+ GDEBUG(" Activation Parameters =%s", buf->str);
+ }
+ g_string_free(buf, TRUE);
+ }
+ } else {
+ GDEBUG(" Data Exchange RF Tech = 0x%02x",
+ ntf->data_exchange_mode);
+ }
+ }
+#endif /* GUTIL_LOG_DEBUG */
+
+ /* Require RF Tech Parameters */
+ if (ntf->mode_param_bytes) {
+ ntf->mode_param = nci_parse_mode_param(mode_param, ntf->mode,
+ ntf->mode_param_bytes, n);
+ if (act_param_bytes) {
+ memset(activation_param, 0, sizeof(*activation_param));
+ ntf->activation_param_len = m;
+ ntf->activation_param_bytes = act_param_bytes;
+ ntf->activation_param =
+ nci_parse_activation_param(activation_param,
+ ntf->rf_intf, ntf->mode, act_param_bytes, m);
+ }
+ return TRUE;
+ }
+ GDEBUG("Missing RF Tech Parameters");
+ }
+ }
+ GDEBUG("Failed to parse RF_INTF_ACTIVATED_NTF");
+ return FALSE;
+}
+
+NciDiscoveryNtf*
+nci_discovery_ntf_copy_array(
+ const NciDiscoveryNtf* const* ntfs,
+ guint count)
+{
+ if (G_LIKELY(count)) {
+ guint i;
+ gsize size = G_ALIGN8(sizeof(NciDiscoveryNtf)*count);
+ NciDiscoveryNtf* copy;
+ guint8* ptr;
+
+ /* Calculate total size */
+ for (i = 0; i < count; i++) {
+ const NciDiscoveryNtf* src = ntfs[i];
+
+ if (src->param_len) {
+ size += G_ALIGN8(src->param_len);
+ if (src->param) {
+ size += G_ALIGN8(sizeof(*src->param));
+ }
+ }
+ }
+
+ /* Deep copy of NciDiscoveryNtf */
+ copy = g_malloc0(size);
+ ptr = (void*)copy;
+ ptr += G_ALIGN8(sizeof(NciDiscoveryNtf)*count);
+ for (i = 0; i < count; i++) {
+ const NciDiscoveryNtf* src = ntfs[i];
+ NciDiscoveryNtf* dest = copy + i;
+
+ *dest = *src;
+ if (src->param_len) {
+ dest->param_bytes = ptr;
+ memcpy(ptr, src->param_bytes, src->param_len);
+ ptr += G_ALIGN8(src->param_len);
+ if (src->param) {
+ NciModeParam* dest_param = (NciModeParam*)ptr;
+
+ *dest_param = *src->param;
+ dest->param = dest_param;
+ ptr += G_ALIGN8(sizeof(*src->param));
+ }
+ }
+ }
+ /* The result can be deallocated with a single g_free call */
+ return copy;
+ } else {
+ return NULL;
+ }
+}
+
+NciDiscoveryNtf*
+nci_discovery_ntf_copy(
+ const NciDiscoveryNtf* ntf)
+{
+ if (G_LIKELY(ntf)) {
+ return nci_discovery_ntf_copy_array(&ntf, 1);
+ } else {
+ return NULL;
+ }
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/nci/src/nci_util.h
^
|
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NCI_UTIL_H
+#define NCI_UTIL_H
+
+#include "nci_types_p.h"
+
+const NciModeParam*
+nci_parse_mode_param(
+ NciModeParam* param,
+ NCI_MODE mode,
+ const guint8* bytes,
+ guint len);
+
+gboolean
+nci_parse_discover_ntf(
+ NciDiscoveryNtf* ntf,
+ NciModeParam* param,
+ const guint8* bytes,
+ guint len);
+
+gboolean
+nci_parse_intf_activated_ntf(
+ NciIntfActivationNtf* ntf,
+ NciModeParam* mode_param,
+ NciActivationParam* activation_param,
+ const guint8* pkt,
+ guint len);
+
+NciDiscoveryNtf*
+nci_discovery_ntf_copy_array(
+ const NciDiscoveryNtf* const* ntfs,
+ guint count);
+
+NciDiscoveryNtf*
+nci_discovery_ntf_copy(
+ const NciDiscoveryNtf* ntf);
+
+#endif /* NCI_UTIL_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Changed |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/src/binder_nfc.h
^
|
@@ -77,6 +77,7 @@
NfcTarget*
binder_nfc_target_new(
+ GBinderRemoteObject* remote,
const NciIntfActivationNtf* ntf,
NciCore* nci);
|
[-]
[+]
|
Changed |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/src/binder_nfc_adapter.c
^
|
@@ -43,6 +43,7 @@
#include <gbinder.h>
#include <gutil_idlequeue.h>
+#include <gutil_idlepool.h>
#include <gutil_misc.h>
#include <gutil_macros.h>
@@ -91,6 +92,7 @@
NfcTarget* target;
char* fqname;
GUtilIdleQueue* idle;
+ GUtilIdlePool* pool;
gboolean core_initialized;
gulong death_id;
@@ -872,7 +874,7 @@
binder_nfc_adapter_drop_target(self);
/* Register the new tag */
- self->target = binder_nfc_target_new(ntf, nci);
+ self->target = binder_nfc_target_new(self->remote, ntf, nci);
/* Figure out what kind of target we are dealing with */
if (mp) {
@@ -1245,6 +1247,7 @@
self->hal_io.fn = &hal_io_functions;
self->idle = gutil_idle_queue_new();
+ self->pool = gutil_idle_pool_new();
self->nci = nci_core_new(&self->hal_io);
self->nci_event_id[CORE_EVENT_CURRENT_STATE] =
@@ -1284,8 +1287,8 @@
nci_core_remove_all_handlers(self->nci, self->nci_event_id);
nci_core_free(self->nci);
+ gutil_idle_pool_destroy(self->pool);
gutil_idle_queue_unref(self->idle);
- gbinder_client_cancel(self->client, self->nci_write_id);
gbinder_client_cancel(self->client, self->pending_tx);
gbinder_client_unref(self->client);
gbinder_local_object_drop(self->callback);
|
[-]
[+]
|
Changed |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/src/binder_nfc_target.c
^
|
@@ -37,6 +37,8 @@
#include <nfc_tag.h>
#include <nfc_target_impl.h>
+#include <gbinder.h>
+
#define T2T_CMD_READ (0x30)
enum {
@@ -58,6 +60,7 @@
typedef NfcTargetClass BinderNfcTargetClass;
struct binder_nfc_target {
NfcTarget target;
+ GBinderRemoteObject* remote;
NciCore* nci;
NCI_RF_INTERFACE rf_intf;
gulong event_id[EVENT_COUNT];
@@ -260,6 +263,7 @@
NfcTarget*
binder_nfc_target_new(
+ GBinderRemoteObject* remote,
const NciIntfActivationNtf* ntf,
NciCore* nci)
{
@@ -319,6 +323,7 @@
break;
}
+ self->remote = gbinder_remote_object_ref(remote);
self->rf_intf = ntf->rf_intf;
self->nci = nci;
self->event_id[EVENT_DATA_PACKET] = nci_core_add_data_packet_handler(nci,
@@ -424,6 +429,7 @@
BinderNfcTarget* self = BINDER_NFC_TARGET(object);
binder_nfc_target_drop_nci(self);
+ gbinder_remote_object_unref(self->remote);
G_OBJECT_CLASS(binder_nfc_target_parent_class)->finalize(object);
}
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/unit/Makefile
^
|
@@ -0,0 +1,15 @@
+# -*- Mode: makefile-gmake -*-
+
+all:
+%:
+ @$(MAKE) -C nci_core $*
+ @$(MAKE) -C nci_sar $*
+ @$(MAKE) -C nci_sm $*
+ @$(MAKE) -C nci_util $*
+
+clean: unitclean
+ rm -f *~
+ rm -f common/*~
+ rm -f coverage/*~
+ rm -f coverage/*.gcov
+ rm -fr coverage/report
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/unit/common/Makefile
^
|
@@ -0,0 +1,189 @@
+# -*- Mode: makefile-gmake -*-
+
+.PHONY: clean all debug release coverage
+.PHONY: debug_lib release_lib coverage_lib
+
+#
+# Real test makefile defines EXE (and possibly SRC) and includes this one.
+#
+
+ifndef EXE
+${error EXE not defined}
+endif
+
+SRC ?= $(EXE).c
+COMMON_SRC ?= test_main.c
+
+#
+# Required packages
+#
+
+PKGS += libglibutil glib-2.0 gobject-2.0
+
+#
+# Default target
+#
+
+all: debug release
+
+#
+# Directories
+#
+
+SRC_DIR = .
+LIB_DIR = ../../nci
+COMMON_DIR = ../common
+BUILD_DIR = build
+DEBUG_BUILD_DIR = $(BUILD_DIR)/debug
+RELEASE_BUILD_DIR = $(BUILD_DIR)/release
+COVERAGE_BUILD_DIR = $(BUILD_DIR)/coverage
+
+#
+# Tools and flags
+#
+
+CC = $(CROSS_COMPILE)gcc
+LD = $(CC)
+WARNINGS += -Wall
+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)
+LIBS = $(shell pkg-config --libs $(PKGS)) -ldl
+QUIET_MAKE = make --no-print-directory
+DEBUG_FLAGS = -g
+RELEASE_FLAGS =
+COVERAGE_FLAGS = -g
+
+DEBUG_LDFLAGS = $(FULL_LDFLAGS) $(DEBUG_FLAGS)
+RELEASE_LDFLAGS = $(FULL_LDFLAGS) $(RELEASE_FLAGS)
+COVERAGE_LDFLAGS = $(FULL_LDFLAGS) $(COVERAGE_FLAGS) --coverage
+
+DEBUG_CFLAGS = $(FULL_CFLAGS) $(DEBUG_FLAGS) -DDEBUG
+RELEASE_CFLAGS = $(FULL_CFLAGS) $(RELEASE_FLAGS) -O2
+COVERAGE_CFLAGS = $(FULL_CFLAGS) $(COVERAGE_FLAGS) --coverage
+
+DEBUG_LIB_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_lib)
+RELEASE_LIB_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_lib)
+COVERAGE_LIB_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_coverage_lib)
+
+DEBUG_LIB = $(LIB_DIR)/$(DEBUG_LIB_FILE)
+RELEASE_LIB = $(LIB_DIR)/$(RELEASE_LIB_FILE)
+COVERAGE_LIB = $(LIB_DIR)/$(COVERAGE_LIB_FILE)
+
+DEBUG_LIBS = $(DEBUG_LIB) $(LIBS)
+RELEASE_LIBS = $(RELEASE_LIB) $(LIBS)
+COVERAGE_LIBS = $(COVERAGE_LIB) $(LIBS)
+
+#
+# Files
+#
+
+DEBUG_OBJS = \
+ $(COMMON_SRC:%.c=$(DEBUG_BUILD_DIR)/common_%.o) \
+ $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
+RELEASE_OBJS = \
+ $(COMMON_SRC:%.c=$(RELEASE_BUILD_DIR)/common_%.o) \
+ $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
+COVERAGE_OBJS = \
+ $(COMMON_SRC:%.c=$(COVERAGE_BUILD_DIR)/common_%.o) \
+ $(SRC:%.c=$(COVERAGE_BUILD_DIR)/%.o)
+
+#
+# Dependencies
+#
+
+DEPS = $(DEBUG_OBJS:%.o=%.d) $(RELEASE_OBJS:%.o=%.d)
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(strip $(DEPS)),)
+-include $(DEPS)
+endif
+endif
+
+$(DEBUG_LIB): | debug_lib
+$(RELEASE_LIB): | release_lib
+$(COVERAGE_LIB): | coverage_lib
+
+$(DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
+$(RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
+$(COVERAGE_OBJS): | $(COVERAGE_BUILD_DIR)
+
+#
+# Rules
+#
+
+DEBUG_EXE = $(DEBUG_BUILD_DIR)/$(EXE)
+RELEASE_EXE = $(RELEASE_BUILD_DIR)/$(EXE)
+COVERAGE_EXE = $(COVERAGE_BUILD_DIR)/$(EXE)
+
+debug: debug_lib $(DEBUG_EXE)
+
+release: release_lib $(RELEASE_EXE)
+
+coverage: coverage_lib $(COVERAGE_EXE)
+
+unitclean:
+ rm -f *~
+ rm -fr $(BUILD_DIR)
+
+clean: unitclean
+
+cleaner: unitclean
+ @make -C $(LIB_DIR) clean
+
+test_banner:
+ @echo "===========" $(EXE) "=========== "
+
+test: test_banner debug
+ @LD_LIBRARY_PATH="$(LIB_DIR)/$(DEBUG_LIB_PATH)" $(DEBUG_EXE)
+
+valgrind: test_banner debug
+ @LD_LIBRARY_PATH="$(LIB_DIR)/$(DEBUG_LIB_PATH)" G_DEBUG=gc-friendly G_SLICE=always-malloc valgrind --tool=memcheck --leak-check=full --show-possibly-lost=no $(DEBUG_EXE)
+
+$(DEBUG_BUILD_DIR):
+ mkdir -p $@
+
+$(RELEASE_BUILD_DIR):
+ mkdir -p $@
+
+$(COVERAGE_BUILD_DIR):
+ mkdir -p $@
+
+$(DEBUG_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
+ $(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
+
+$(RELEASE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
+ $(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
+
+$(COVERAGE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
+ $(CC) -c $(COVERAGE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
+
+$(DEBUG_BUILD_DIR)/common_%.o : $(COMMON_DIR)/%.c
+ $(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
+
+$(RELEASE_BUILD_DIR)/common_%.o : $(COMMON_DIR)/%.c
+ $(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
+
+$(COVERAGE_BUILD_DIR)/common_%.o : $(COMMON_DIR)/%.c
+ $(CC) -c $(COVERAGE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
+
+$(DEBUG_EXE): $(DEBUG_LIB) $(DEBUG_OBJS)
+ $(LD) $(DEBUG_LDFLAGS) $(DEBUG_OBJS) $(DEBUG_LIBS) -o $@
+
+$(RELEASE_EXE): $(RELEASE_LIB) $(RELEASE_OBJS)
+ $(LD) $(RELEASE_LDFLAGS) $(RELEASE_OBJS) $(RELEASE_LIBS) -o $@
+
+$(COVERAGE_EXE): $(COVERAG_LIB) $(COVERAGE_OBJS)
+ $(LD) $(COVERAGE_LDFLAGS) $(COVERAGE_OBJS) $(COVERAGE_LIBS) -o $@
+
+debug_lib:
+ $(MAKE) -C $(LIB_DIR) $@
+
+release_lib:
+ $(MAKE) -C $(LIB_DIR) $@
+
+coverage_lib:
+ $(MAKE) -C $(LIB_DIR) $@
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/unit/common/test_common.h
^
|
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2018-2019 Jolla Ltd.
+ * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TEST_COMMON_H
+#define TEST_COMMON_H
+
+#include <gutil_types.h>
+
+#define TEST_FLAG_DEBUG (0x01)
+typedef struct test_opt {
+ int flags;
+} TestOpt;
+
+/* Should be invoked after g_test_init */
+void
+test_init(
+ TestOpt* opt,
+ int argc,
+ char* argv[]);
+
+/* Run loop with a timeout */
+void
+test_run(
+ const TestOpt* opt,
+ GMainLoop* loop);
+
+/* Quits the event loop on the next iteration (or after n iterations) */
+void
+test_quit_later(
+ GMainLoop* loop);
+
+void
+test_quit_later_n(
+ GMainLoop* loop,
+ guint n);
+
+#define TEST_TIMEOUT_SEC (20)
+
+/* Helper macros */
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+# define TEST_INT16_BYTES(v) \
+ (guint8)(v), (guint8)((v) >> 8)
+# define TEST_INT32_BYTES(v) \
+ (guint8)(v), (guint8)((v) >> 8), \
+ (guint8)((v) >> 16), (guint8)((v) >> 24)
+# define TEST_INT64_BYTES(v) \
+ (guint8)(v), (guint8)((v) >> 8), \
+ (guint8)((v) >> 16), (guint8)((v) >> 24), \
+ (guint8)(((guint64)(v)) >> 32), (guint8)(((guint64)(v)) >> 40), \
+ (guint8)(((guint64)(v)) >> 48), (guint8)(((guint64)(v)) >> 56)
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+# define TEST_INT16_BYTES(v) \
+ (guint8)((v) >> 8), (guint8)(v)
+# define TEST_INT32_BYTES(v) \
+ (guint8)((v) >> 24), (guint8)((v) >> 16), \
+ (guint8)((v) >> 8), (guint8)(v)
+# define TEST_INT64_BYTES(v) \
+ (guint8)(((guint64)(v)) >> 56), (guint8)(((guint64)(v)) >> 48), \
+ (guint8)(((guint64)(v)) >> 40), (guint8)(((guint64)(v)) >> 32), \
+ (guint8)((v) >> 24), (guint8)((v) >> 16), \
+ (guint8)((v) >> 8), (guint8)(v)
+#else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
+#error unknown ENDIAN type
+#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
+
+#define TEST_ARRAY_AND_COUNT(a) a, G_N_ELEMENTS(a)
+#define TEST_ARRAY_AND_SIZE(a) a, sizeof(a)
+#define TEST_BYTES_SET(b,d) ((b).bytes = (void*)(d), (b).size = sizeof(d))
+
+#endif /* TEST_COMMON_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/unit/common/test_main.c
^
|
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018-2019 Jolla Ltd.
+ * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "test_common.h"
+
+#include <gutil_log.h>
+
+static
+gboolean
+test_timeout_expired(
+ gpointer data)
+{
+ g_assert(!"TIMEOUT");
+ return G_SOURCE_REMOVE;
+}
+
+typedef struct test_quit_later_data{
+ GMainLoop* loop;
+ guint n;
+} TestQuitLaterData;
+
+static
+void
+test_quit_later_n_free(
+ gpointer user_data)
+{
+ TestQuitLaterData* data = user_data;
+
+ g_main_loop_unref(data->loop);
+ g_free(data);
+}
+
+static
+gboolean
+test_quit_later_n_func(
+ gpointer user_data)
+{
+ TestQuitLaterData* data = user_data;
+
+ if (data->n > 0) {
+ data->n--;
+ return G_SOURCE_CONTINUE;
+ } else {
+ g_main_loop_quit(data->loop);
+ return G_SOURCE_REMOVE;
+ }
+}
+
+void
+test_quit_later_n(
+ GMainLoop* loop,
+ guint n)
+{
+ TestQuitLaterData* data = g_new0(TestQuitLaterData, 1);
+
+ data->loop = g_main_loop_ref(loop);
+ data->n = n;
+ g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, test_quit_later_n_func, data,
+ test_quit_later_n_free);
+}
+
+void
+test_quit_later(
+ GMainLoop* loop)
+{
+ test_quit_later_n(loop, 0);
+}
+
+void
+test_run(
+ const TestOpt* opt,
+ GMainLoop* loop)
+{
+ if (opt->flags & TEST_FLAG_DEBUG) {
+ g_main_loop_run(loop);
+ } else {
+ const guint timeout_id = g_timeout_add_seconds(TEST_TIMEOUT_SEC,
+ test_timeout_expired, NULL);
+ g_main_loop_run(loop);
+ g_source_remove(timeout_id);
+ }
+}
+
+void
+test_init(
+ TestOpt* opt,
+ int argc,
+ char* argv[])
+{
+ const char* sep1;
+ const char* sep2;
+ int i;
+
+ memset(opt, 0, sizeof(*opt));
+ for (i=1; i<argc; i++) {
+ const char* arg = argv[i];
+ if (!strcmp(arg, "-d") || !strcmp(arg, "--debug")) {
+ opt->flags |= TEST_FLAG_DEBUG;
+ } else if (!strcmp(arg, "-v")) {
+ GTestConfig* config = (GTestConfig*)g_test_config_vars;
+ config->test_verbose = TRUE;
+ } else {
+ GWARN("Unsupported command line option %s", arg);
+ }
+ }
+
+ /* Setup logging */
+ sep1 = strrchr(argv[0], '/');
+ sep2 = strrchr(argv[0], '\\');
+ gutil_log_default.name = (sep1 && sep2) ? (MAX(sep1, sep2) + 1) :
+ sep1 ? (sep1 + 1) : sep2 ? (sep2 + 1) : argv[0];
+ gutil_log_default.level = g_test_verbose() ?
+ GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
+ gutil_log_timestamp = FALSE;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/unit/coverage/.gitignore
^
|
@@ -0,0 +1,2 @@
+report
+*.gcov
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/unit/coverage/run
^
|
@@ -0,0 +1,52 @@
+#!/bin/bash
+#
+# This script requires lcov, dirname
+#
+
+TESTS="\
+nci_core \
+nci_sar \
+nci_sm \
+nci_util"
+
+function err() {
+ echo "*** ERROR!" $1
+ exit 1
+}
+
+# Check the required tools
+which lcov >> /dev/null || err "Please install lcov"
+which dirname >> /dev/null || err "Please install dirname"
+
+# LCOV 1.10 has branch coverage disabled per default
+# Previous versions didn't have the --rc option
+if [ ! -z "$(lcov --help | grep ' --rc ')" ] ; then
+ LCOV_OPT="--rc lcov_branch_coverage=1"
+ GENHTML_OPT="--branch-coverage"
+fi
+
+pushd `dirname $0` > /dev/null
+COV_DIR="$PWD"
+pushd .. > /dev/null
+TEST_DIR="$PWD"
+pushd .. > /dev/null
+TOP_DIR="$PWD"
+LIB_DIR="$TOP_DIR/nci"
+popd > /dev/null
+popd > /dev/null
+popd > /dev/null
+
+make -C "$TOP_DIR" clean
+for t in $TESTS ; do
+ pushd "$TEST_DIR/$t"
+ make -C "$TEST_DIR/$t" clean coverage || exit 1
+ build/coverage/test_$t || exit 1
+ popd
+done
+
+FULL_COV="$COV_DIR/full.gcov"
+LIB_COV="$COV_DIR/lib.gcov"
+rm -f "$FULL_COV" "$LIB_COV"
+lcov $LCOV_OPT -c -d "$LIB_DIR/build/coverage" -b "$LIB_DIR/src" -o "$FULL_COV" || exit 1
+lcov $LCOV_OPT -e "$FULL_COV" "$LIB_DIR/src/*" -o "$LIB_COV" || exit 1
+genhtml $GENHTML_OPT "$LIB_COV" -t "NCI core" --output-directory "$COV_DIR/report" || exit 1
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/unit/nci_core/Makefile
^
|
@@ -0,0 +1,5 @@
+# -*- Mode: makefile-gmake -*-
+
+EXE = test_nci_core
+
+include ../common/Makefile
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/unit/nci_core/test_nci_core.c
^
|
@@ -0,0 +1,2216 @@
+/*
+ * Copyright (C) 2018-2019 Jolla Ltd.
+ * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "test_common.h"
+
+#include "nci_core.h"
+#include "nci_hal.h"
+#include "nci_sm.h"
+
+#include <gutil_macros.h>
+#include <gutil_log.h>
+
+static TestOpt test_opt;
+
+#define TEST_TIMEOUT (20) /* seconds */
+#define TEST_DEFAULT_CMD_TIMEOUT (10000) /* milliseconds */
+
+static const guint8 CORE_RESET_RSP[] = {
+ 0x40, 0x00, 0x03, 0x00, 0x10, 0x00
+};
+static const guint8 CORE_RESET_RSP_ERROR[] = {
+ 0x40, 0x00, 0x03, 0x03, 0x10, 0x00
+};
+static const guint8 CORE_RESET_V2_RSP[] = {
+ 0x40, 0x00, 0x01, 0x00
+};
+static const guint8 CORE_RESET_V2_NTF[] = {
+ 0x60, 0x00, 0x1f, 0x02, 0x01, 0x20, 0x02, 0x1a,
+ 0x04, 0x04, 0x01, 0x03, 0x63, 0x94, 0x02, 0x02,
+ 0x00, 0x59, 0xc0, 0xc0, 0x1b, 0x59, 0xc0, 0x89,
+ 0x7f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x42,
+ 0x22, 0x01
+};
+static const guint8 CORE_RESET_RSP_BROKEN[] = {
+ 0x40, 0x00, 0x02, 0x00, 0x00
+};
+static const guint8 CORE_INIT_RSP[] = {
+ 0x40, 0x01, 0x19, 0x00, 0x03, 0x0e, 0x02, 0x00,
+ 0x08, 0x00, 0x01, 0x02, 0x03, 0x80, 0x82, 0x83,
+ 0x84, 0x02, 0x5c, 0x03, 0xff, 0x02, 0x00, 0x04,
+ 0x41, 0x11, 0x01, 0x18
+};
+static const guint8 CORE_INIT_RSP_1[] = {
+ 0x40, 0x01, 0x19, 0x00, 0x03, 0x0e, 0x02, 0x00,
+ 0x08, 0x00, 0x01, 0x02, 0x03, 0x80, 0x82, 0x83,
+ 0x84, 0x02, 0x5c, 0x03, 0xff, 0x02, 0x00, 0x04,
+ 0x41, 0x11, 0x01, 0x1a
+};
+static const guint8 CORE_INIT_V2_RSP[] = {
+ 0x40, 0x01, 0x18, 0x00, 0x1a, 0x7e, 0x06, 0x00,
+ 0x02, 0x00, 0x02, 0xff, 0xff, 0x00, 0x0c, 0x01,
+ 0x05, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x90, 0x00
+};
+static const guint8 CORE_INIT_V2_RSP_NO_PROTOCOL_ROUTING[] = {
+ 0x40, 0x01, 0x18, 0x00, 0x1a, 0x7a, 0x06, 0x00,
+ 0x02, 0x00, 0x02, 0xff, 0xff, 0x00, 0x0c, 0x01,
+ 0x05, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x90, 0x00
+};
+static const guint8 CORE_INIT_V2_RSP_NO_TECHNOLOGY_ROUTING[] = {
+ 0x40, 0x01, 0x18, 0x00, 0x1a, 0x7c, 0x06, 0x00,
+ 0x02, 0x00, 0x02, 0xff, 0xff, 0x00, 0x0c, 0x01,
+ 0x05, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x90, 0x00
+};
+static const guint8 CORE_INIT_V2_RSP_NO_ROUTING[] = {
+ 0x40, 0x01, 0x18, 0x00, 0x1a, 0x70, 0x06, 0x00,
+ 0x02, 0x00, 0x02, 0xff, 0xff, 0x00, 0x0c, 0x01,
+ 0x05, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x90, 0x00
+};
+static const guint8 CORE_INIT_V2_RSP_ERROR[] = {
+ 0x40, 0x01, 0x0e, 0x03, 0x1a, 0x7e, 0x06, 0x00,
+ 0x02, 0x00, 0x02, 0xff, 0xff, 0x00, 0x0c, 0x01,
+ 0x00
+};
+static const guint8 CORE_INIT_V2_RSP_BROKEN1[] = {
+ 0x40, 0x01, 0x10, 0x00, 0x1a, 0x7e, 0x06, 0x00,
+ 0x02, 0x00, 0x02, 0xff, 0xff, 0x00, 0x0c, 0x01,
+ 0x05, 0x01, 0x00
+};
+static const guint8 CORE_INIT_V2_RSP_BROKEN2[] = {
+ 0x40, 0x01, 0x01, 0x03
+};
+static const guint8 CORE_INIT_RSP_BROKEN[] = {
+ 0x40, 0x01, 0x00
+};
+static const guint8 CORE_GET_CONFIG_RSP[] = {
+ 0x40, 0x03, 0x0b, 0x00, 0x03, 0x08, 0x01, 0x00,
+ 0x11, 0x01, 0x00, 0x22, 0x01, 0x00
+};
+static const guint8 CORE_GET_CONFIG_RSP_ERROR[] = {
+ 0x40, 0x03, 0x02, 0x03, 0x00
+};
+static const guint8 CORE_GET_CONFIG_RSP_INVALID_PARAM[] = {
+ 0x40, 0x03, 0x04, NCI_STATUS_INVALID_PARAM, 0x01, 0x11, 0x00
+};
+static const guint8 CORE_GET_CONFIG_BROKEN[] = {
+ 0x40, 0x03, 0x00
+};
+static const guint8 CORE_SET_CONFIG_RSP[] = {
+ 0x40, 0x02, 0x02, 0x00, 0x00
+};
+static const guint8 CORE_SET_CONFIG_RSP_ERROR[] = {
+ 0x40, 0x02, 0x02, NCI_STATUS_REJECTED, 0x00
+};
+static const guint8 CORE_SET_CONFIG_RSP_INVALID_PARAM[] = {
+ 0x40, 0x02, 0x03, NCI_STATUS_INVALID_PARAM, 0x01, 0x11
+};
+static const guint8 RF_SET_LISTEN_MODE_ROUTING_RSP[] = {
+ 0x41, 0x01, 0x01, 0x00
+};
+static const guint8 RF_SET_LISTEN_MODE_ROUTING_RSP_ERROR[] = {
+ 0x41, 0x01, 0x01, 0x01
+};
+static const guint8 RF_SET_LISTEN_MODE_ROUTING_RSP_BROKEN[] = {
+ 0x41, 0x01, 0x00
+};
+static const guint8 RF_DISCOVER_MAP_RSP[] = {
+ 0x41, 0x00, 0x01, 0x00
+};
+static const guint8 RF_DISCOVER_MAP_ERROR[] = {
+ 0x41, 0x00, 0x01, 0x03
+};
+static const guint8 RF_DISCOVER_MAP_BROKEN[] = {
+ 0x41, 0x00, 0x00
+};
+static const guint8 RF_DISCOVER_RSP[] = {
+ 0x41, 0x03, 0x01, 0x00
+};
+static const guint8 RF_DISCOVER_RSP_ERROR[] = {
+ 0x41, 0x03, 0x01, 0x03
+};
+static const guint8 RF_DISCOVER_RSP_BROKEN[] = {
+ 0x41, 0x03, 0x00
+};
+static const guint8 RF_INTF_ACTIVATED_NTF_T2[] = {
+ 0x61, 0x05, 0x17, 0x01, 0x01, 0x02, 0x00, 0xff,
+ 0x01, 0x0c, 0x44, 0x00, 0x07, 0x04, 0x9b, 0xfb,
+ 0x4a, 0xeb, 0x2b, 0x80, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00
+};
+static const guint8 RF_INTF_ACTIVATED_NTF_ISO_DEP[] = {
+ 0x61, 0x05, 0x1f, 0x01, 0x02, 0x04, 0x00, 0xff,
+ 0x01, 0x09, 0x04, 0x00, 0x04, 0x4f, 0x01, 0x74,
+ 0x01, 0x01, 0x20, 0x00, 0x00, 0x00, 0x0b, 0x0a,
+ 0x78, 0x80, 0x81, 0x02, 0x4b, 0x4f, 0x4e, 0x41,
+ 0x14, 0x11
+};
+static const guint8 RF_INTF_ACTIVATED_NTF_T2_BROKEN1[] = {
+ 0x61, 0x05, 0x05 /* Too short */, 0x01, 0x01, 0x02, 0x00, 0xff
+};
+static const guint8 RF_INTF_ACTIVATED_NTF_T2_BROKEN2[] = {
+ 0x61, 0x05, 0x14 /* Still too short */, 0x01, 0x01, 0x02, 0x00, 0xff,
+ 0x01, 0x0c, 0x44, 0x00, 0x07, 0x04, 0x9b, 0xfb,
+ 0x4a, 0xeb, 0x2b, 0x80, 0x01, 0x00, 0x00
+};
+static const guint8 RF_INTF_ACTIVATED_NTF_T2_BROKEN3[] = {
+ 0x61, 0x05, 0x0b, 0x01, 0x01, 0x02, 0x00, 0xff,
+ 0x01, 0x00 /* Missing RF Tech Parameters */, 0x00, 0x00, 0x00, 0x00
+};
+static const guint8 RF_INTF_ACTIVATED_NTF_T4A[] = {
+ 0x61, 0x05, 0x27, 0x01, 0x02, 0x04, 0x00, 0xff,
+ 0x01, 0x09, 0x04, 0x00, 0x04, 0x37, 0xf4, 0x95,
+ 0x95, 0x01, 0x20, 0x00, 0x00, 0x00, 0x13, 0x12,
+ 0x78, 0x80, 0x72, 0x02, 0x80, 0x31, 0x80, 0x66,
+ 0xb1, 0x84, 0x0c, 0x01, 0x6e, 0x01, 0x83, 0x00,
+ 0x90, 0x00
+};
+static const guint8 RF_INTF_ACTIVATED_NTF_T4A_BROKEN1[] = {
+ 0x61, 0x05, 0x27, 0x01, 0x02, 0x04, 0x00, 0xff,
+ 0x01, 0x09, 0x04, 0x00, 0x04, 0x37, 0xf4, 0x95,
+ 0x95, 0x01, 0x20, 0x00, 0x00, 0x00, 0x14 /* One too many */, 0x12,
+ 0x78, 0x80, 0x72, 0x02, 0x80, 0x31, 0x80, 0x66,
+ 0xb1, 0x84, 0x0c, 0x01, 0x6e, 0x01, 0x83, 0x00,
+ 0x90, 0x00
+};
+static const guint8 RF_INTF_ACTIVATED_NTF_T4A_BROKEN_ACT_PARAM1[] = {
+ 0x61, 0x05, 0x27, 0x01, 0x02, 0x04, 0x00, 0xff,
+ 0x01, 0x09, 0x04, 0x00, 0x04, 0x37, 0xf4, 0x95,
+ 0x95, 0x01, 0x20, 0x00, 0x00, 0x00, 0x13, 0x13 /* One too many */,
+ 0x78, 0x80, 0x72, 0x02, 0x80, 0x31, 0x80, 0x66,
+ 0xb1, 0x84, 0x0c, 0x01, 0x6e, 0x01, 0x83, 0x00,
+ 0x90, 0x00
+};
+static const guint8 RF_INTF_ACTIVATED_NTF_T4A_BROKEN_ACT_PARAM2[] = {
+ 0x61, 0x05, 0x15, 0x01, 0x02, 0x04, 0x00, 0xff,
+ 0x01, 0x09, 0x04, 0x00, 0x04, 0x37, 0xf4, 0x95,
+ 0x95, 0x01, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00 /* Missing params */,
+};
+static const guint8 RF_DEACTIVATE_RSP[] = {
+ 0x41, 0x06, 0x01, 0x00
+};
+static const guint8 RF_DEACTIVATE_RSP_ERROR[] = {
+ 0x41, 0x06, 0x01, 0x03
+};
+static const guint8 RF_DEACTIVATE_RSP_BROKEN[] = {
+ 0x41, 0x06, 0x00
+};
+static const guint8 RF_DEACTIVATE_NTF_IDLE[] = {
+ 0x61, 0x06, 0x02, 0x00, 0x00
+};
+static const guint8 RF_DEACTIVATE_NTF_DISCOVERY[] = {
+ 0x61, 0x06, 0x02, 0x03, 0x00
+};
+static const guint8 RF_DEACTIVATE_NTF_BROKEN[] = {
+ 0x61, 0x06, 0x00
+};
+static const guint8 CORE_GENERIC_ERROR_NTF[] = {
+ 0x60, 0x07, 0x01, NCI_STATUS_FAILED
+};
+static const guint8 CORE_GENERIC_TARGET_ACTIVATION_FAILED_ERROR_NTF[] = {
+ 0x60, 0x07, 0x01, NCI_DISCOVERY_TARGET_ACTIVATION_FAILED
+};
+static const guint8 CORE_GENERIC_ERROR_NTF_BROKEN[] = {
+ 0x60, 0x07, 0x00
+};
+static const guint8 CORE_CONN_CREDITS_NTF[] = {
+ 0x60, 0x06, 0x03, 0x01, 0x00, 0x01
+};
+static const guint8 CORE_CONN_CREDITS_BROKEN1_NTF[] = {
+ 0x60, 0x06, 0x00
+};
+static const guint8 CORE_CONN_CREDITS_BROKEN2_NTF[] = {
+ 0x60, 0x06, 0x02, 0x01, 0x00
+};
+static const guint8 CORE_INTERFACE_GENERIC_ERROR_NTF[] = {
+ 0x60, 0x08, 0x02, NCI_STATUS_FAILED, 0x00
+};
+static const guint8 CORE_INTERFACE_TRANSMISSION_ERROR_NTF[] = {
+ 0x60, 0x08, 0x02, NCI_RF_TRANSMISSION_ERROR, 0x00
+};
+static const guint8 CORE_INTERFACE_PROTOCOL_ERROR_NTF[] = {
+ 0x60, 0x08, 0x02, NCI_RF_PROTOCOL_ERROR, 0x00
+};
+static const guint8 CORE_INTERFACE_TIMEOUT_ERROR_NTF[] = {
+ 0x60, 0x08, 0x02, NCI_RF_TIMEOUT_ERROR, 0x00
+};
+static const guint8 CORE_INTERFACE_ERROR_NTF_BROKEN[] = {
+ 0x60, 0x08, 0x01, NCI_STATUS_FAILED
+};
+static const guint8 CORE_IGNORED_NTF[] = {
+ 0x60, 0x33, 0x00
+};
+static const guint8 RF_IGNORED_NTF[] = {
+ 0x61, 0x33, 0x00
+};
+static const guint8 NFCEE_IGNORED_NTF[] = {
+ 0x62, 0x33, 0x00
+};
+static const guint8 RF_DISCOVER_NTF_1_ISO_DEP[] = {
+ 0x61, 0x03, 0x0e, 0x01, 0x04, 0x00, 0x09, 0x04,
+ 0x00, 0x04, 0x4f, 0x01, 0x74, 0x01, 0x01, 0x20,
+ 0x02
+};
+static const guint8 RF_DISCOVER_NTF_2_T2T[] = {
+ 0x61, 0x03, 0x0e, 0x02, 0x02, 0x00, 0x09, 0x04,
+ 0x00, 0x04, 0x4f, 0x01, 0x74, 0x01, 0x01, 0x08,
+ 0x02
+};
+static const guint8 RF_DISCOVER_NTF_2_PROPRIETARY_LAST[] = {
+ 0x61, 0x03, 0x0e, 0x02, 0x80, 0x00, 0x09, 0x04,
+ 0x00, 0x04, 0x4f, 0x01, 0x74, 0x01, 0x01, 0x08,
+ 0x00
+};
+static const guint8 RF_DISCOVER_NTF_3_PROPRIETARY_LAST[] = {
+ 0x61, 0x03, 0x0e, 0x03, 0x81, 0x00, 0x09, 0x04,
+ 0x00, 0x04, 0x4f, 0x01, 0x74, 0x01, 0x01, 0x08,
+ 0x00
+};
+static const guint8 RF_DISCOVER_SELECT_RSP[] = {
+ 0x41, 0x04, 0x01, 0x00
+};
+
+static
+gboolean
+test_timeout(
+ gpointer loop)
+{
+ g_assert(!"TIMEOUT");
+ return G_SOURCE_REMOVE;
+}
+
+static
+guint
+test_setup_timeout(
+ GMainLoop* loop)
+{
+ if (!(test_opt.flags & TEST_FLAG_DEBUG)) {
+ return g_timeout_add_seconds(TEST_TIMEOUT, test_timeout, loop);
+ } else {
+ return 0;
+ }
+}
+
+static
+void
+test_bytes_unref(
+ gpointer bytes)
+{
+ g_bytes_unref(bytes);
+}
+
+/*==========================================================================*
+ * Dummy HAL
+ *==========================================================================*/
+
+static
+gboolean
+test_dummy_hal_io_start(
+ NciHalIo* io,
+ NciHalClient* client)
+{
+ return FALSE;
+}
+
+static
+void
+test_dummy_hal_io_stop(
+ NciHalIo* io)
+{
+}
+
+static
+gboolean
+test_dummy_hal_io_write(
+ NciHalIo* io,
+ const GUtilData* chunks,
+ guint count,
+ NciHalClientFunc complete)
+{
+ return FALSE;
+}
+
+static
+void
+test_dummy_hal_io_cancel_write(
+ NciHalIo* io)
+{
+}
+
+static const NciHalIoFunctions test_dummy_hal_io_fn = {
+ .start = test_dummy_hal_io_start,
+ .stop = test_dummy_hal_io_stop,
+ .write = test_dummy_hal_io_write,
+ .cancel_write = test_dummy_hal_io_cancel_write
+};
+
+static NciHalIo test_dummy_hal_io = {
+ .fn = &test_dummy_hal_io_fn
+};
+
+/*==========================================================================*
+ * Test HAL
+ *==========================================================================*/
+
+typedef struct test_hal_io {
+ NciHalIo io;
+ GPtrArray* read_queue;
+ GPtrArray* written;
+ guint write_id;
+ guint read_id;
+ NciHalClient* sar;
+ void* test_data;
+ guint fail_write;
+} TestHalIo;
+
+typedef struct test_hal_io_read {
+ TestHalIo* hal;
+ GBytes* bytes;
+ gboolean spontaneous;
+} TestHalIoRead;
+
+typedef struct test_hal_io_write {
+ TestHalIo* hal;
+ GBytes* bytes;
+ NciHalClientFunc complete;
+} TestHalIoWrite;
+
+static
+void
+test_hal_io_read_free(
+ gpointer user_data)
+{
+ TestHalIoRead* read = user_data;
+
+ g_bytes_unref(read->bytes);
+ g_free(read);
+}
+
+static
+void
+test_hal_io_write_free(
+ gpointer user_data)
+{
+ TestHalIoWrite* write = user_data;
+
+ g_bytes_unref(write->bytes);
+ g_free(write);
+}
+
+static
+gboolean
+test_hal_io_next_rsp(
+ TestHalIo* hal)
+{
+ GPtrArray* queue = hal->read_queue;
+
+ if (queue && queue->len && hal->sar) {
+ TestHalIoRead* read = queue->pdata[0];
+
+ return !read->spontaneous;
+ }
+ return FALSE;
+}
+
+static
+gboolean
+test_hal_io_next_ntf(
+ TestHalIo* hal)
+{
+ GPtrArray* queue = hal->read_queue;
+
+ if (queue && queue->len && hal->sar) {
+ TestHalIoRead* read = queue->pdata[0];
+
+ return read->spontaneous;
+ }
+ return FALSE;
+}
+
+static
+void
+test_hal_io_read_one(
+ TestHalIo* hal)
+{
+ GPtrArray* queue = hal->read_queue;
+ TestHalIoRead* read = queue->pdata[0];
+ GBytes* bytes = g_bytes_ref(read->bytes);
+ gsize len;
+ const void* data = g_bytes_get_data(bytes, &len);
+
+ g_ptr_array_remove_index(queue, 0);
+ hal->sar->fn->read(hal->sar, data, len);
+ g_bytes_unref(bytes);
+}
+
+static
+void
+test_hal_io_flush_ntf(
+ TestHalIo* hal)
+{
+ while (test_hal_io_next_ntf(hal)) {
+ test_hal_io_read_one(hal);
+ }
+}
+
+static
+gboolean
+test_hal_io_read_cb(
+ gpointer user_data)
+{
+ TestHalIo* hal = user_data;
+
+ hal->read_id = 0;
+ test_hal_io_flush_ntf(hal);
+ if (test_hal_io_next_rsp(hal)) {
+ test_hal_io_read_one(hal);
+ test_hal_io_flush_ntf(hal);
+ }
+ return G_SOURCE_REMOVE;
+}
+
+static
+gboolean
+test_hal_io_write_cb(
+ gpointer user_data)
+{
+ TestHalIoWrite* write = user_data;
+ TestHalIo* hal = write->hal;
+
+ g_assert(hal->write_id);
+ hal->write_id = 0;
+ g_ptr_array_add(hal->written, g_bytes_ref(write->bytes));
+ if (write->complete) {
+ write->complete(hal->sar, TRUE);
+ }
+ if (!hal->read_id) {
+ hal->read_id = g_idle_add(test_hal_io_read_cb, hal);
+ }
+ return G_SOURCE_REMOVE;
+}
+
+static
+gboolean
+test_hal_io_start(
+ NciHalIo* io,
+ NciHalClient* sar)
+{
+ TestHalIo* hal = G_CAST(io, TestHalIo, io);
+
+ g_assert(!hal->read_id);
+ g_assert(!hal->sar);
+ hal->sar = sar;
+ if (test_hal_io_next_ntf(hal)) {
+ hal->read_id = g_idle_add(test_hal_io_read_cb, hal);
+ }
+ return TRUE;
+}
+static
+void
+test_hal_io_stop(
+ NciHalIo* io)
+{
+ TestHalIo* hal = G_CAST(io, TestHalIo, io);
+
+ g_assert(hal->sar);
+ hal->sar = NULL;
+ if (hal->read_queue) {
+ g_ptr_array_set_size(hal->read_queue, 0);
+ }
+ if (hal->read_id) {
+ g_source_remove(hal->read_id);
+ hal->read_id = 0;
+ }
+ if (hal->write_id) {
+ g_source_remove(hal->write_id);
+ hal->write_id = 0;
+ }
+}
+
+static
+gboolean
+test_hal_io_write(
+ NciHalIo* io,
+ const GUtilData* chunks,
+ guint count,
+ NciHalClientFunc complete)
+{
+ TestHalIo* hal = G_CAST(io, TestHalIo, io);
+
+ if (hal->fail_write) {
+ hal->fail_write--;
+ GDEBUG("Simulating write failure");
+ return FALSE;
+ } else {
+ TestHalIoWrite* write = g_new0(TestHalIoWrite, 1);
+ GByteArray* packet = g_byte_array_new();
+ guint i;
+
+ g_assert(count > 0);
+ for (i = 0; i < count; i++) {
+ g_byte_array_append(packet, chunks[i].bytes, chunks[i].size);
+ }
+
+ g_assert(hal->sar);
+ g_assert(!hal->write_id);
+ write->hal = hal;
+ write->bytes = g_byte_array_free_to_bytes(packet);
+ write->complete = complete;
+ hal->write_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
+ test_hal_io_write_cb, write, test_hal_io_write_free);
+ return TRUE;
+ }
+}
+
+static
+void
+test_hal_io_cancel_write(
+ NciHalIo* io)
+{
+ TestHalIo* hal = G_CAST(io, TestHalIo, io);
+
+ g_assert(hal->write_id);
+ g_source_remove(hal->write_id);
+ hal->write_id = 0;
+}
+
+static
+TestHalIo*
+test_hal_io_new_with_functions(
+ const NciHalIoFunctions* fn)
+{
+ TestHalIo* hal = g_new0(TestHalIo, 1);
+
+ hal->io.fn = fn;
+ hal->written = g_ptr_array_new();
+ g_ptr_array_set_free_func(hal->written, test_bytes_unref);
+ return hal;
+}
+
+static
+TestHalIo*
+test_hal_io_new(
+ void)
+{
+ static const NciHalIoFunctions test_hal_io_fn = {
+ .start = test_hal_io_start,
+ .stop = test_hal_io_stop,
+ .write = test_hal_io_write,
+ .cancel_write = test_hal_io_cancel_write
+ };
+
+ return test_hal_io_new_with_functions(&test_hal_io_fn);
+}
+
+static
+void
+test_hal_io_queue_read(
+ TestHalIo* hal,
+ const void* data,
+ guint len,
+ gboolean spontaneous)
+{
+ TestHalIoRead* read = g_new0(TestHalIoRead, 1);
+
+ if (!hal->read_queue) {
+ hal->read_queue = g_ptr_array_new();
+ g_ptr_array_set_free_func(hal->read_queue, test_hal_io_read_free);
+ }
+
+ read->hal = hal;
+ read->bytes = g_bytes_new(data, len);
+ read->spontaneous = spontaneous;
+ g_ptr_array_add(hal->read_queue, read);
+ if (!hal->read_id && test_hal_io_next_ntf(hal)) {
+ hal->read_id = g_idle_add(test_hal_io_read_cb, hal);
+ }
+}
+
+#define test_hal_io_queue_rsp(hal,rsp) \
+ test_hal_io_queue_read(hal, TEST_ARRAY_AND_SIZE(rsp), FALSE)
+#define test_hal_io_queue_ntf(hal,ntf) \
+ test_hal_io_queue_read(hal, TEST_ARRAY_AND_SIZE(ntf), TRUE)
+
+static
+void
+test_hal_io_free(
+ TestHalIo* hal)
+{
+ g_assert(!hal->sar);
+ g_assert(!hal->write_id);
+ g_ptr_array_free(hal->written, TRUE);
+ if (hal->read_queue) {
+ g_ptr_array_free(hal->read_queue, TRUE);
+ }
+ g_free(hal);
+}
+
+/*==========================================================================*
+ * null
+ *==========================================================================*/
+
+static
+void
+test_null(
+ void)
+{
+ NciCore* nci = nci_core_new(&test_dummy_hal_io);
+
+ g_assert(!nci_core_new(NULL));
+ g_assert(!nci_core_send_data_msg(NULL, 0, NULL, NULL, NULL, NULL));
+ g_assert(!nci_core_add_current_state_changed_handler(NULL, NULL, NULL));
+ g_assert(!nci_core_add_next_state_changed_handler(NULL, NULL, NULL));
+ g_assert(!nci_core_add_intf_activated_handler(NULL, NULL, NULL));
+ g_assert(!nci_core_add_data_packet_handler(NULL, NULL, NULL));
+
+ g_assert(!nci_core_add_current_state_changed_handler(nci, NULL, NULL));
+ g_assert(!nci_core_add_next_state_changed_handler(nci, NULL, NULL));
+ g_assert(!nci_core_add_intf_activated_handler(nci, NULL, NULL));
+ g_assert(!nci_core_add_data_packet_handler(nci, NULL, NULL));
+ nci_core_remove_handler(nci, 0);
+
+ nci_core_set_state(NULL, NCI_STATE_INIT);
+ nci_core_cancel(NULL, 0);
+ nci_core_remove_handler(NULL, 0);
+ nci_core_restart(NULL);
+ nci_core_free(NULL);
+
+ nci_core_free(nci);
+}
+
+/*==========================================================================*
+ * restart
+ *==========================================================================*/
+
+static
+void
+test_restart_done(
+ NciCore* nci,
+ void* user_data)
+{
+ g_assert(nci->current_state == NCI_RFST_IDLE);
+ test_quit_later((GMainLoop*)user_data);
+}
+
+static
+void
+test_restart(
+ void)
+{
+ TestHalIo* hal = test_hal_io_new();
+ NciCore* nci = nci_core_new(&hal->io);
+ GMainLoop* loop = g_main_loop_new(NULL, TRUE);
+ guint timeout_id = test_setup_timeout(loop);
+ gulong id;
+
+ nci->cmd_timeout = (test_opt.flags & TEST_FLAG_DEBUG) ? 0 :
+ TEST_DEFAULT_CMD_TIMEOUT;
+
+ /* Responses */
+ test_hal_io_queue_rsp(hal, CORE_RESET_RSP);
+ test_hal_io_queue_ntf(hal, CORE_IGNORED_NTF);
+ test_hal_io_queue_rsp(hal, CORE_INIT_RSP);
+ test_hal_io_queue_rsp(hal, CORE_GET_CONFIG_RSP);
+ test_hal_io_queue_rsp(hal, CORE_SET_CONFIG_RSP);
+
+ id = nci_core_add_current_state_changed_handler(nci,
+ test_restart_done, loop);
+
+ nci_core_restart(nci);
+ g_main_loop_run(loop);
+ if (timeout_id) {
+ g_source_remove(timeout_id);
+ }
+
+ g_assert(nci->current_state == NCI_RFST_IDLE);
+ g_assert(nci->next_state == NCI_RFST_IDLE);
+ nci_core_remove_handler(nci, id);
+
+ nci_core_free(nci);
+ test_hal_io_free(hal);
+ g_main_loop_unref(loop);
+}
+
+/*==========================================================================*
+ * init_ok
+ *==========================================================================*/
+
+static
+void
+test_init_ok_done(
+ NciCore* nci,
+ void* user_data)
+{
+ g_assert(nci->current_state == NCI_RFST_IDLE);
+ test_quit_later((GMainLoop*)user_data);
+}
+
+static
+void
+test_init_ok(
+ void)
+{
+ TestHalIo* hal = test_hal_io_new();
+ NciCore* nci = nci_core_new(&hal->io);
+ GMainLoop* loop = g_main_loop_new(NULL, TRUE);
+ guint timeout_id;
+ gulong id;
+
+ /* Second time does nothing */
+ nci_core_set_state(nci, NCI_RFST_IDLE);
+ nci_core_set_state(nci, NCI_RFST_IDLE);
+ /* Couple of error notifications (ignored) */
+ test_hal_io_queue_ntf(hal, CORE_GENERIC_ERROR_NTF_BROKEN);
+ test_hal_io_queue_ntf(hal, CORE_GENERIC_ERROR_NTF);
+ /* Responses */
+ test_hal_io_queue_rsp(hal, CORE_RESET_RSP);
+ test_hal_io_queue_ntf(hal, CORE_IGNORED_NTF);
+ /* Couple more broken notifications */
+ test_hal_io_queue_ntf(hal, CORE_CONN_CREDITS_BROKEN1_NTF);
+ test_hal_io_queue_ntf(hal, CORE_CONN_CREDITS_BROKEN2_NTF);
+ /* Final response */
+ test_hal_io_queue_rsp(hal, CORE_INIT_RSP);
+ /* SET_CONFIG errors are ignored */
+ test_hal_io_queue_rsp(hal, CORE_GET_CONFIG_RSP_ERROR);
+ /* SET_CONFIG errors are ignored too */
+ test_hal_io_queue_rsp(hal, CORE_SET_CONFIG_RSP_ERROR);
+ /* And a valid notification */
+ test_hal_io_queue_ntf(hal, CORE_CONN_CREDITS_NTF);
+ /* Two more error notifications (ignored) */
+ test_hal_io_queue_ntf(hal, CORE_GENERIC_ERROR_NTF_BROKEN);
+ test_hal_io_queue_ntf(hal, CORE_GENERIC_ERROR_NTF);
+
+ id = nci_core_add_current_state_changed_handler(nci,
+ test_init_ok_done, loop);
+
+ timeout_id = test_setup_timeout(loop);
+ g_main_loop_run(loop);
+ if (timeout_id) {
+ g_source_remove(timeout_id);
+ }
+
+ g_assert(nci->current_state == NCI_RFST_IDLE);
+ g_assert(nci->next_state == NCI_RFST_IDLE);
+ nci_core_remove_handlers(nci, &id, 1);
+ g_assert(!id);
+ nci_core_free(nci);
+ test_hal_io_free(hal);
+ g_main_loop_unref(loop);
+}
+
+/*==========================================================================*
+ * init_failed1
+ *==========================================================================*/
+
+static
+void
+test_init_failed1_done(
+ NciCore* nci,
+ void* user_data)
+{
+ g_assert(nci->current_state == NCI_STATE_ERROR);
+ test_quit_later((GMainLoop*)user_data);
+}
+
+static
+void
+test_init_failed1(
+ void)
+{
+ NciCore* nci = nci_core_new(&test_dummy_hal_io);
+ GMainLoop* loop = g_main_loop_new(NULL, TRUE);
+ guint timeout_id;
+ gulong id;
+
+ nci_core_set_state(nci, NCI_RFST_IDLE);
+ id = nci_core_add_current_state_changed_handler(nci,
+ test_init_failed1_done, loop);
+
+ timeout_id = test_setup_timeout(loop);
+ g_main_loop_run(loop);
+ if (timeout_id) {
+ g_source_remove(timeout_id);
+ }
+
+ g_assert(nci->current_state == NCI_STATE_ERROR);
+ g_assert(nci->next_state == NCI_STATE_ERROR);
+ nci_core_remove_handler(nci, id);
+ nci_core_free(nci);
+ g_main_loop_unref(loop);
+}
+
+/*==========================================================================*
+ * init_failed2
+ *==========================================================================*/
+
+static
+void
+test_init_failed2_done(
+ NciCore* nci,
+ void* user_data)
+{
+ g_assert(nci->current_state == NCI_STATE_ERROR);
+ test_quit_later((GMainLoop*)user_data);
+}
+
+static
+void
+test_init_failed2(
+ void)
+{
+ TestHalIo* hal = test_hal_io_new();
+ NciCore* nci;
+ GMainLoop* loop;
+ guint timeout_id;
+ gulong id;
+
+ hal->fail_write++;
+ nci = nci_core_new(&hal->io);
+ loop = g_main_loop_new(NULL, TRUE);
+ nci_core_set_state(nci, NCI_RFST_IDLE);
+ id = nci_core_add_current_state_changed_handler(nci,
+ test_init_failed2_done, loop);
+
+ timeout_id = test_setup_timeout(loop);
+ g_main_loop_run(loop);
+ if (timeout_id) {
+ g_source_remove(timeout_id);
+ }
+
+ g_assert(nci->current_state == NCI_STATE_ERROR);
+ g_assert(nci->next_state == NCI_STATE_ERROR);
+ nci_core_remove_handler(nci, id);
+ nci_core_free(nci);
+ test_hal_io_free(hal);
+ g_main_loop_unref(loop);
+}
+
+/*==========================================================================*
+ * nci_sm
+ *==========================================================================*/
+
+typedef struct test_nci_sm_entry TestSmEntry;
+typedef struct test_nci_sm_entry_set_timeout TestSmEntrySetTimeout;
+typedef struct test_nci_sm_entry_send_data TestSmEntrySendData;
+typedef struct test_nci_sm_entry_queue_read TestSmEntryQueueRead;
+typedef struct test_nci_sm_entry_assert_states TestSmEntryAssertStates;
+typedef struct test_nci_sm_entry_state TestSmEntryState;
+typedef struct test_nci_sm_entry_activation TestEntryActivation;
+
+typedef struct test_nci_sm_data {
+ const char* name;
+ const TestSmEntry* entries;
+} TestNciSmData;
+
+typedef struct test_nci_sm {
+ TestHalIo* hal;
+ NciCore* nci;
+ GMainLoop* loop;
+ const TestNciSmData* data;
+ const TestSmEntry* entry;
+} TestNciSm;
+
+struct test_nci_sm_entry {
+ void (*func)(TestNciSm* test);
+ union {
+ struct test_nci_sm_entry_set_timeout {
+ guint ms;
+ } set_timeout;
+ struct test_nci_sm_entry_send_data {
+ const void* data;
+ guint len;
+ guint8 cid;
+ } send_data;
+ struct test_nci_sm_entry_queue_read {
+ const void* data;
+ guint len;
+ gboolean ntf;
+ } queue_read;
+ struct test_nci_sm_entry_assert_states {
+ NCI_STATE current_state;
+ NCI_STATE next_state;
+ } assert_states;
+ struct test_nci_sm_entry_state {
+ NCI_STATE state;
+ } state;
+ struct test_nci_sm_entry_activation {
+ NCI_RF_INTERFACE rf_intf;
+ NCI_PROTOCOL protocol;
+ NCI_MODE mode;
+ } activation;
+ } data;
+};
+
+#define TEST_NCI_SM_SET_TIMEOUT(millis) { \
+ .func = test_nci_sm_set_timeout, \
+ .data.set_timeout = { .ms = millis } }
+#define TEST_NCI_SM_RF_SEND(bytes) { \
+ .func = test_nci_sm_send_data, \
+ .data.send_data = { .data = bytes, .len = sizeof(bytes), \
+ .cid = NCI_STATIC_RF_CONN_ID } }
+#define TEST_NCI_SM_QUEUE_RSP(bytes) { \
+ .func = test_nci_sm_queue_read, \
+ .data.queue_read = { .data = bytes, .len = sizeof(bytes), .ntf = FALSE } }
+#define TEST_NCI_SM_QUEUE_NTF(bytes) { \
+ .func = test_nci_sm_queue_read, \
+ .data.queue_read = { .data = bytes, .len = sizeof(bytes), .ntf = TRUE } }
+#define TEST_NCI_SM_ASSERT_STATES(current,next) { \
+ .func = test_nci_sm_assert_states, \
+ .data.assert_states = { .current_state = current, .next_state = next } }
+#define TEST_NCI_SM_ASSERT_STATE(state) { \
+ .func = test_nci_sm_assert_states, \
+ .data.assert_states = { .current_state = state, .next_state = state } }
+#define TEST_NCI_SM_SET_STATE(next_state) { \
+ .func = test_nci_sm_set_state, \
+ .data.state = { .state = next_state } }
+#define TEST_NCI_SM_WAIT_STATE(wait_state) { \
+ .func = test_nci_sm_wait_state, \
+ .data.state = { .state = wait_state } }
+#define TEST_NCI_SM_WAIT_ACTIVATION(intf,prot,mod) { \
+ .func = test_nci_sm_wait_activation, \
+ .data.activation = { .rf_intf = intf, .protocol = prot, .mode = mod } }
+#define TEST_NCI_SM_END() { .func = NULL }
+
+static
+void
+test_nci_sm_set_timeout(
+ TestNciSm* test)
+{
+ NciCore* nci = test->nci;
+ const TestSmEntrySetTimeout* timeout = &test->entry->data.set_timeout;
+
+ GDEBUG("Timeout %u ms", timeout->ms);
+ nci->cmd_timeout = timeout->ms;
+}
+
+static
+void
+test_nci_sm_send_data_cb(
+ NciCore* nci,
+ gboolean success,
+ void* user_data)
+{
+ g_assert(success);
+}
+
+static
+void
+test_nci_sm_send_data(
+ TestNciSm* test)
+{
+ const TestSmEntrySendData* send = &test->entry->data.send_data;
+ GBytes* bytes = g_bytes_new(send->data, send->len);
+
+ g_assert(nci_core_send_data_msg(test->nci, send->cid, bytes,
+ test_nci_sm_send_data_cb, test_bytes_unref, bytes));
+}
+
+static
+void
+test_nci_sm_queue_read(
+ TestNciSm* test)
+{
+ const TestSmEntryQueueRead* queue_read = &test->entry->data.queue_read;
+
+ test_hal_io_queue_read(test->hal, queue_read->data, queue_read->len,
+ queue_read->ntf);
+}
+
+static
+void
+test_nci_sm_assert_states(
+ TestNciSm* test)
+{
+ NciCore* nci = test->nci;
+ const TestSmEntryAssertStates* assert_states =
+ &test->entry->data.assert_states;
+
+ g_assert(assert_states->current_state == nci->current_state);
+ g_assert(assert_states->next_state == nci->next_state);
+}
+
+static
+void
+test_nci_sm_set_state(
+ TestNciSm* test)
+{
+ nci_core_set_state(test->nci, test->entry->data.state.state);
+}
+
+static
+void
+test_nci_sm_wait_state_cb(
+ NciCore* nci,
+ void* user_data)
+{
+ TestNciSm* test = user_data;
+ const TestSmEntryState* wait = &test->entry->data.state;
+
+ GDEBUG("Current state %d", nci->current_state);
+ g_assert(nci == test->nci);
+ if (nci->current_state == wait->state) {
+ test_quit_later(test->loop);
+ }
+}
+
+static
+void
+test_nci_sm_wait_state(
+ TestNciSm* test)
+{
+ NciCore* nci = test->nci;
+ const TestSmEntryState* wait = &test->entry->data.state;
+
+ test_hal_io_flush_ntf(test->hal);
+ if (nci->current_state == wait->state) {
+ GDEBUG("No need to wait, the state is already %d", wait->state);
+ } else {
+ gulong id = nci_core_add_current_state_changed_handler(nci,
+ test_nci_sm_wait_state_cb, test);
+
+ GDEBUG("Waiting for state %d", wait->state);
+ g_main_loop_run(test->loop);
+ nci_core_remove_handler(nci, id);
+ g_assert(nci->current_state == wait->state);
+ }
+}
+
+static
+void
+test_nci_sm_wait_activation_cb(
+ NciCore* nci,
+ const NciIntfActivationNtf* ntf,
+ void* user_data)
+{
+ TestNciSm* test = user_data;
+ const TestEntryActivation* wait = &test->entry->data.activation;
+
+ GDEBUG("Activation %u/%u/%u", ntf->rf_intf, ntf->protocol, ntf->mode);
+ g_assert(nci == test->nci);
+ if (ntf->rf_intf == wait->rf_intf &&
+ ntf->protocol == wait->protocol &&
+ ntf->mode == wait->mode) {
+ test_quit_later(test->loop);
+ }
+}
+
+static
+void
+test_nci_sm_wait_activation(
+ TestNciSm* test)
+{
+ NciCore* nci = test->nci;
+ const TestEntryActivation* wait = &test->entry->data.activation;
+ gulong id = nci_core_add_intf_activated_handler(nci,
+ test_nci_sm_wait_activation_cb, test);
+
+ GDEBUG("Waiting for %u/%u/%u activation", wait->rf_intf,
+ wait->protocol, wait->mode);
+ test_hal_io_flush_ntf(test->hal);
+ g_main_loop_run(test->loop);
+ nci_core_remove_handler(nci, id);
+}
+
+static
+void
+test_nci_sm(
+ gconstpointer user_data)
+{
+ TestNciSm test;
+ guint timeout_id;
+
+ memset(&test, 0, sizeof(test));
+ test.hal = test_hal_io_new();
+ test.nci = nci_core_new(&test.hal->io);
+ test.loop = g_main_loop_new(NULL, TRUE);
+ test.data = user_data;
+ test.entry = test.data->entries;
+
+ test.nci->cmd_timeout = (test_opt.flags & TEST_FLAG_DEBUG) ? 0 :
+ TEST_DEFAULT_CMD_TIMEOUT;
+ timeout_id = test_setup_timeout(test.loop);
+ while (test.entry->func) {
+ test.entry->func(&test);
+ test.entry++;
+ }
+ if (timeout_id) {
+ g_source_remove(timeout_id);
+ }
+
+ nci_core_free(test.nci);
+ test_hal_io_free(test.hal);
+ g_main_loop_unref(test.loop);
+}
+
+/* State machine tests */
+
+static const TestSmEntry test_nci_sm_init_ok[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_init_timeout[] = {
+ TEST_NCI_SM_SET_TIMEOUT(500),
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ /* No CORE_INIT_RSP */
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_get_config_timeout[] = {
+ TEST_NCI_SM_SET_TIMEOUT(500),
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ /* No CORE_GET_CONFIG_RSP */
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_set_config_timeout[] = {
+ TEST_NCI_SM_SET_TIMEOUT(500),
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ /* No CORE_SET_CONFIG_RSP */
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_init_v2[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_V2_RSP),
+ TEST_NCI_SM_QUEUE_NTF(CORE_RESET_V2_NTF),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_V2_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_init_v2_error[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_V2_RSP),
+ TEST_NCI_SM_QUEUE_NTF(CORE_RESET_V2_NTF),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_V2_RSP_ERROR),
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_init_v2_broken1[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_V2_RSP),
+ TEST_NCI_SM_QUEUE_NTF(CORE_RESET_V2_NTF),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_V2_RSP_BROKEN1),
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_init_v2_broken2[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_V2_RSP),
+ TEST_NCI_SM_QUEUE_NTF(CORE_RESET_V2_NTF),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_V2_RSP_BROKEN2),
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_reset_failed[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP_ERROR),
+ TEST_NCI_SM_QUEUE_NTF(CORE_RESET_RSP), /* Ignored */
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_reset_broken[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP_BROKEN),
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_init_broken[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_NTF(CORE_RESET_V2_NTF), /* Unexpected (ignored) */
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP_BROKEN),
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_get_config_error[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ /* GET_CONFIG errors are ignored */
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP_INVALID_PARAM),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_get_config_broken[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_BROKEN),
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_ignore_unexpected_rsp[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP), /* Unexpected (ignored) */
+ TEST_NCI_SM_QUEUE_NTF(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_failed[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP_ERROR),
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_broken[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP_BROKEN),
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_v2[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_ASSERT_STATES(NCI_STATE_INIT, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_V2_RSP),
+ TEST_NCI_SM_QUEUE_NTF(CORE_RESET_V2_NTF),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_V2_RSP_NO_ROUTING),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_IDLE),
+
+ TEST_NCI_SM_ASSERT_STATES(NCI_RFST_IDLE, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_v2_protocol[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_ASSERT_STATES(NCI_STATE_INIT, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_V2_RSP),
+ TEST_NCI_SM_QUEUE_NTF(CORE_RESET_V2_NTF),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_V2_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_IDLE),
+
+ TEST_NCI_SM_ASSERT_STATES(NCI_RFST_IDLE, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_SET_LISTEN_MODE_ROUTING_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_v2_protocol_error[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_ASSERT_STATES(NCI_STATE_INIT, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_V2_RSP),
+ TEST_NCI_SM_QUEUE_NTF(CORE_RESET_V2_NTF),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_V2_RSP_NO_TECHNOLOGY_ROUTING),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_IDLE),
+
+ TEST_NCI_SM_ASSERT_STATES(NCI_RFST_IDLE, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_SET_LISTEN_MODE_ROUTING_RSP_ERROR),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_v2_technology1[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_ASSERT_STATES(NCI_STATE_INIT, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_V2_RSP),
+ TEST_NCI_SM_QUEUE_NTF(CORE_RESET_V2_NTF),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_V2_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_IDLE),
+
+ TEST_NCI_SM_ASSERT_STATES(NCI_RFST_IDLE, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_SET_LISTEN_MODE_ROUTING_RSP_ERROR),
+ TEST_NCI_SM_QUEUE_RSP(RF_SET_LISTEN_MODE_ROUTING_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_v2_technology2[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_ASSERT_STATES(NCI_STATE_INIT, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_V2_RSP),
+ TEST_NCI_SM_QUEUE_NTF(CORE_RESET_V2_NTF),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_V2_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_IDLE),
+
+ TEST_NCI_SM_ASSERT_STATES(NCI_RFST_IDLE, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_SET_LISTEN_MODE_ROUTING_RSP_BROKEN),
+ TEST_NCI_SM_QUEUE_RSP(RF_SET_LISTEN_MODE_ROUTING_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_v2_technology3[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_ASSERT_STATES(NCI_STATE_INIT, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_V2_RSP),
+ TEST_NCI_SM_QUEUE_NTF(CORE_RESET_V2_NTF),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_V2_RSP_NO_PROTOCOL_ROUTING),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_IDLE),
+
+ TEST_NCI_SM_ASSERT_STATES(NCI_RFST_IDLE, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_SET_LISTEN_MODE_ROUTING_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_v2_technology4[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_ASSERT_STATES(NCI_STATE_INIT, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_V2_RSP),
+ TEST_NCI_SM_QUEUE_NTF(CORE_RESET_V2_NTF),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_V2_RSP_NO_PROTOCOL_ROUTING),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_IDLE),
+
+ TEST_NCI_SM_ASSERT_STATES(NCI_RFST_IDLE, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_SET_LISTEN_MODE_ROUTING_RSP_BROKEN),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_v2_technology5[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_ASSERT_STATES(NCI_STATE_INIT, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_V2_RSP),
+ TEST_NCI_SM_QUEUE_NTF(CORE_RESET_V2_NTF),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_V2_RSP_NO_PROTOCOL_ROUTING),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_IDLE),
+
+ TEST_NCI_SM_ASSERT_STATES(NCI_RFST_IDLE, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_SET_LISTEN_MODE_ROUTING_RSP_ERROR),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discover_map_error[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_ERROR),
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discover_map_broken[] = {
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_BROKEN),
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_idle_discovery[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_QUEUE_NTF(CORE_GENERIC_ERROR_NTF), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(CORE_IGNORED_NTF), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(CORE_CONN_CREDITS_NTF),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_ASSERT_STATES(NCI_STATE_INIT, NCI_RFST_IDLE),
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_ASSERT_STATES(NCI_STATE_INIT, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_NTF(RF_IGNORED_NTF), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(NFCEE_IGNORED_NTF), /* Ignored */
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* And then switch back to IDLE */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_ASSERT_STATES(NCI_RFST_DISCOVERY, NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP),
+ TEST_NCI_SM_QUEUE_NTF(CORE_IGNORED_NTF),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_IDLE),
+
+ /* And again to DISCOVERY */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_ASSERT_STATES(NCI_RFST_IDLE, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_idle_failed[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_ASSERT_STATES(NCI_STATE_INIT, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_QUEUE_NTF(CORE_CONN_CREDITS_NTF),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* And then switch back to IDLE (and fail) */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_ASSERT_STATES(NCI_RFST_DISCOVERY, NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP_ERROR),
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_idle_broken[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_ASSERT_STATES(NCI_STATE_INIT, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_QUEUE_NTF(CORE_CONN_CREDITS_NTF),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* And then switch back to IDLE (and fail) */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_ASSERT_STATES(NCI_RFST_DISCOVERY, NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP_BROKEN),
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_poll_idle[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_ASSERT_STATES(NCI_STATE_INIT, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Simulate activation */
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_T2),
+ TEST_NCI_SM_QUEUE_NTF(CORE_IGNORED_NTF), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(NFCEE_IGNORED_NTF), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(CORE_CONN_CREDITS_NTF),
+ TEST_NCI_SM_WAIT_ACTIVATION(NCI_RF_INTERFACE_FRAME,
+ NCI_PROTOCOL_T2T, NCI_MODE_PASSIVE_POLL_A),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+
+ /* And then switch back to IDLE */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_NTF(CORE_IGNORED_NTF), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(RF_IGNORED_NTF), /* Ignored */
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP),
+ TEST_NCI_SM_QUEUE_NTF(RF_DEACTIVATE_NTF_IDLE),
+ TEST_NCI_SM_QUEUE_NTF(RF_IGNORED_NTF), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(NFCEE_IGNORED_NTF), /* Ignored */
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_poll_idle_failed[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_ASSERT_STATES(NCI_STATE_INIT, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Simulate activation */
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_T2),
+ TEST_NCI_SM_QUEUE_NTF(CORE_CONN_CREDITS_NTF),
+ TEST_NCI_SM_WAIT_ACTIVATION(NCI_RF_INTERFACE_FRAME,
+ NCI_PROTOCOL_T2T, NCI_MODE_PASSIVE_POLL_A),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+
+ /* And then switch back to IDLE (and fail) */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP_ERROR),
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_poll_idle_broken1[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_ASSERT_STATES(NCI_STATE_INIT, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Simulate activation */
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_T2),
+ TEST_NCI_SM_QUEUE_NTF(CORE_CONN_CREDITS_NTF),
+ TEST_NCI_SM_WAIT_ACTIVATION(NCI_RF_INTERFACE_FRAME,
+ NCI_PROTOCOL_T2T, NCI_MODE_PASSIVE_POLL_A),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+
+ /* And then switch back to IDLE (and fail) */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP_BROKEN),
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_poll_idle_broken2[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_ASSERT_STATES(NCI_STATE_INIT, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Simulate activation */
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_T2),
+ TEST_NCI_SM_QUEUE_NTF(CORE_CONN_CREDITS_NTF),
+ TEST_NCI_SM_WAIT_ACTIVATION(NCI_RF_INTERFACE_FRAME,
+ NCI_PROTOCOL_T2T, NCI_MODE_PASSIVE_POLL_A),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+
+ /* And then switch back to IDLE (and fail) */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP),
+ TEST_NCI_SM_QUEUE_NTF(RF_DEACTIVATE_NTF_BROKEN),
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_poll_discovery[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_ASSERT_STATES(NCI_STATE_INIT, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Simulate activation */
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_T2),
+ TEST_NCI_SM_QUEUE_NTF(CORE_CONN_CREDITS_NTF),
+ TEST_NCI_SM_WAIT_ACTIVATION(NCI_RF_INTERFACE_FRAME,
+ NCI_PROTOCOL_T2T, NCI_MODE_PASSIVE_POLL_A),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+
+ /* And then switch back to DISCOVERY */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP),
+ TEST_NCI_SM_QUEUE_NTF(CORE_IGNORED_NTF), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(RF_IGNORED_NTF), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(NFCEE_IGNORED_NTF), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(RF_DEACTIVATE_NTF_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Another activation */
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_T2),
+ TEST_NCI_SM_QUEUE_NTF(CORE_CONN_CREDITS_NTF),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+
+ /* And then to IDLE */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP),
+ TEST_NCI_SM_QUEUE_NTF(RF_DEACTIVATE_NTF_IDLE),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_dscvr_poll_dscvr_error1[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Simulate activation */
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_T2),
+ TEST_NCI_SM_WAIT_ACTIVATION(NCI_RF_INTERFACE_FRAME,
+ NCI_PROTOCOL_T2T, NCI_MODE_PASSIVE_POLL_A),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+
+ /* And then switch back to DISCOVERY (and fail) */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP_ERROR), /* Fail to Discovery */
+
+ /* Switch to to Idle instead */
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_dscvr_poll_dscvr_error2[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Simulate activation */
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_T2),
+ TEST_NCI_SM_WAIT_ACTIVATION(NCI_RF_INTERFACE_FRAME,
+ NCI_PROTOCOL_T2T, NCI_MODE_PASSIVE_POLL_A),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+
+ /* And then switch back to DISCOVERY (and fail) */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP_ERROR), /* Fail to Discovery */
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP_ERROR), /* Fail to Idle */
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_dscvr_poll_dscvr_error3[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Simulate activation */
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_T2),
+ TEST_NCI_SM_WAIT_ACTIVATION(NCI_RF_INTERFACE_FRAME,
+ NCI_PROTOCOL_T2T, NCI_MODE_PASSIVE_POLL_A),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+
+ /* And then switch back to DISCOVERY (and fail) */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP_ERROR), /* Fail to Discovery */
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP_BROKEN), /* Fail to Idle */
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_dscvr_poll_dscvr_broken[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Simulate activation */
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_T2),
+ TEST_NCI_SM_WAIT_ACTIVATION(NCI_RF_INTERFACE_FRAME,
+ NCI_PROTOCOL_T2T, NCI_MODE_PASSIVE_POLL_A),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+
+ /* And then switch back to DISCOVERY (and fail) */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP_ERROR), /* Fail to Discovery */
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP_ERROR), /* Fail to Idle */
+ TEST_NCI_SM_WAIT_STATE(NCI_STATE_ERROR),
+ TEST_NCI_SM_END()
+};
+
+static const guint8 READ_CMD[] = {
+ 0x00, 0x00, 0x02, 0x30, 0x00
+};
+
+static const guint8 READ_RESP[] = {
+ 0x00, 0x00, 0x11, 0x04, 0x9b, 0xfb, 0xec, 0x4a,
+ 0xeb, 0x2b, 0x80, 0x0a, 0x48, 0x00, 0x00, 0xe1,
+ 0x10, 0x12, 0x00, 0x00,
+};
+
+static const TestSmEntry test_nci_sm_dscvr_poll_read_dscvr[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_ASSERT_STATES(NCI_STATE_INIT, NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Activation */
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_T2),
+ TEST_NCI_SM_WAIT_ACTIVATION(NCI_RF_INTERFACE_FRAME,
+ NCI_PROTOCOL_T2T, NCI_MODE_PASSIVE_POLL_A),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+
+ /* Read sector 0 */
+ TEST_NCI_SM_RF_SEND(READ_CMD),
+ TEST_NCI_SM_QUEUE_NTF(CORE_CONN_CREDITS_NTF),
+ TEST_NCI_SM_QUEUE_NTF(READ_RESP),
+
+ /* Deactivate to DISCOVERY */
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP),
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_NTF(RF_DEACTIVATE_NTF_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_dscvr_poll_deact_t4a[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Activation */
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_T4A),
+ TEST_NCI_SM_WAIT_ACTIVATION(NCI_RF_INTERFACE_ISO_DEP,
+ NCI_PROTOCOL_ISO_DEP, NCI_MODE_PASSIVE_POLL_A),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+
+ /* Make sure these notifications don't change the state */
+ TEST_NCI_SM_QUEUE_NTF(RF_IGNORED_NTF), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(CORE_INTERFACE_ERROR_NTF_BROKEN), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(CORE_INTERFACE_GENERIC_ERROR_NTF), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(CORE_INTERFACE_TRANSMISSION_ERROR_NTF),
+ TEST_NCI_SM_QUEUE_NTF(CORE_INTERFACE_PROTOCOL_ERROR_NTF),
+ TEST_NCI_SM_QUEUE_NTF(CORE_INTERFACE_TIMEOUT_ERROR_NTF),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+
+ /* Deactivate to IDLE */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_ASSERT_STATES(NCI_RFST_POLL_ACTIVE, NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP),
+ TEST_NCI_SM_QUEUE_NTF(RF_DEACTIVATE_NTF_IDLE),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_dscvr_poll_act_error1[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Broken activation switches state machine to DISCOVERY */
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_T2_BROKEN1),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP),
+ TEST_NCI_SM_QUEUE_NTF(RF_DEACTIVATE_NTF_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_dscvr_poll_act_error2[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Broken activation switches state machine to DISCOVERY */
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_T2_BROKEN2),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP),
+ TEST_NCI_SM_QUEUE_NTF(RF_DEACTIVATE_NTF_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_dscvr_poll_act_error3[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Broken activation switches state machine to DISCOVERY */
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_T2_BROKEN3),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP),
+ TEST_NCI_SM_QUEUE_NTF(RF_DEACTIVATE_NTF_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_dscvr_poll_act_error4[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Broken activation switches state machine to DISCOVERY */
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_T4A_BROKEN1),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP),
+ TEST_NCI_SM_QUEUE_NTF(RF_DEACTIVATE_NTF_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_dscvr_poll_deact_t4a_badparam1[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Activation */
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_T4A_BROKEN_ACT_PARAM1),
+ TEST_NCI_SM_WAIT_ACTIVATION(NCI_RF_INTERFACE_ISO_DEP,
+ NCI_PROTOCOL_ISO_DEP, NCI_MODE_PASSIVE_POLL_A),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+
+ /* Deactivate to IDLE */
+ TEST_NCI_SM_SET_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_ASSERT_STATES(NCI_RFST_POLL_ACTIVE, NCI_RFST_IDLE),
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP),
+ TEST_NCI_SM_QUEUE_NTF(RF_DEACTIVATE_NTF_IDLE),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_dscvr_poll_deact_t4a_badparam2[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Activation (missing activation parameters, not a fatal error) */
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_T4A_BROKEN_ACT_PARAM2),
+ TEST_NCI_SM_WAIT_ACTIVATION(NCI_RF_INTERFACE_ISO_DEP,
+ NCI_PROTOCOL_ISO_DEP, NCI_MODE_PASSIVE_POLL_A),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_ntf_t2t[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP_1),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Receive 3 discovery notifications (T2T, ISO-DEP, Proprietary) */
+ TEST_NCI_SM_QUEUE_NTF(RF_DISCOVER_NTF_1_ISO_DEP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_W4_ALL_DISCOVERIES),
+ TEST_NCI_SM_QUEUE_NTF(RF_DISCOVER_NTF_2_T2T),
+ TEST_NCI_SM_QUEUE_NTF(RF_DISCOVER_NTF_3_PROPRIETARY_LAST),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_W4_HOST_SELECT),
+
+ /* Select Type 2 interface */
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_SELECT_RSP),
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_T2),
+ TEST_NCI_SM_WAIT_ACTIVATION(NCI_RF_INTERFACE_FRAME,
+ NCI_PROTOCOL_T2T, NCI_MODE_PASSIVE_POLL_A),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+ TEST_NCI_SM_END()
+};
+
+static const TestSmEntry test_nci_sm_discovery_ntf_isodep[] = {
+ TEST_NCI_SM_QUEUE_RSP(CORE_RESET_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_INIT_RSP_1),
+ TEST_NCI_SM_QUEUE_RSP(CORE_GET_CONFIG_RSP),
+ TEST_NCI_SM_QUEUE_RSP(CORE_SET_CONFIG_RSP),
+
+ /* Switch state machine to DISCOVERY state */
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_MAP_RSP),
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_RSP),
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_DISCOVERY),
+
+ /* Receive 2 discovery notifications (ISO-DEP, and Proprietary) */
+ TEST_NCI_SM_QUEUE_NTF(RF_DISCOVER_NTF_1_ISO_DEP),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_W4_ALL_DISCOVERIES),
+ TEST_NCI_SM_QUEUE_NTF(RF_DISCOVER_NTF_2_PROPRIETARY_LAST),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_W4_HOST_SELECT),
+
+ /* Make sure these notifications don't change the state */
+ TEST_NCI_SM_QUEUE_NTF(RF_IGNORED_NTF), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(CORE_IGNORED_NTF), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(NFCEE_IGNORED_NTF), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(CORE_GENERIC_ERROR_NTF), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(CORE_GENERIC_ERROR_NTF_BROKEN), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(CORE_GENERIC_TARGET_ACTIVATION_FAILED_ERROR_NTF),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_W4_HOST_SELECT),
+
+ /* Select ISO-DEP interface */
+ TEST_NCI_SM_QUEUE_RSP(RF_DISCOVER_SELECT_RSP),
+ TEST_NCI_SM_QUEUE_NTF(CORE_IGNORED_NTF), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(RF_IGNORED_NTF), /* Ignored */
+ TEST_NCI_SM_QUEUE_NTF(RF_INTF_ACTIVATED_NTF_ISO_DEP),
+ TEST_NCI_SM_WAIT_ACTIVATION(NCI_RF_INTERFACE_ISO_DEP,
+ NCI_PROTOCOL_ISO_DEP, NCI_MODE_PASSIVE_POLL_A),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_POLL_ACTIVE),
+
+ /* Try to deactivate to DISCOVERY */
+ TEST_NCI_SM_QUEUE_NTF(CORE_INTERFACE_TIMEOUT_ERROR_NTF),
+ TEST_NCI_SM_SET_STATE(NCI_RFST_DISCOVERY),
+ TEST_NCI_SM_QUEUE_RSP(RF_DEACTIVATE_RSP),
+
+ /* But end up in IDLE */
+ TEST_NCI_SM_QUEUE_NTF(RF_DEACTIVATE_NTF_IDLE),
+ TEST_NCI_SM_WAIT_STATE(NCI_RFST_IDLE),
+ TEST_NCI_SM_END()
+};
+
+const const TestNciSmData nci_sm_tests[] = {
+ { "init-ok", test_nci_sm_init_ok },
+ { "init-timeout", test_nci_sm_init_timeout },
+ { "get-config-timeout", test_nci_sm_get_config_timeout },
+ { "set-config-timeout", test_nci_sm_set_config_timeout },
+ { "init-v2", test_nci_sm_init_v2 },
+ { "init-v2-error", test_nci_sm_init_v2_error },
+ { "init-v2-broken1", test_nci_sm_init_v2_broken1 },
+ { "init-v2-broken2", test_nci_sm_init_v2_broken2 },
+ { "reset-failed", test_nci_sm_reset_failed },
+ { "reset-broken", test_nci_sm_reset_broken },
+ { "init-broken", test_nci_sm_init_broken },
+ { "get-config-error", test_nci_sm_get_config_error },
+ { "get-config-broken", test_nci_sm_get_config_broken },
+ { "ignore-unexpected-rsp", test_nci_sm_ignore_unexpected_rsp },
+ { "discovery-failed", test_nci_sm_discovery_failed },
+ { "discovery-broken", test_nci_sm_discovery_broken },
+ { "discovery-v2", test_nci_sm_discovery_v2 },
+ { "discovery-v2-protocol", test_nci_sm_discovery_v2_protocol },
+ { "discovery-v2-protocol-error", test_nci_sm_discovery_v2_protocol_error },
+ { "discovery-v2-technology1", test_nci_sm_discovery_v2_technology1 },
+ { "discovery-v2-technology2", test_nci_sm_discovery_v2_technology2 },
+ { "discovery-v2-technology3", test_nci_sm_discovery_v2_technology3 },
+ { "discovery-v2-technology4", test_nci_sm_discovery_v2_technology4 },
+ { "discovery-v2-technology5", test_nci_sm_discovery_v2_technology5 },
+ { "discovery-discover-map-error", test_nci_sm_discover_map_error },
+ { "discovery-discover-map-broken", test_nci_sm_discover_map_broken },
+ { "discovery-idle-discovery", test_nci_sm_discovery_idle_discovery },
+ { "discovery-idle-failed", test_nci_sm_discovery_idle_failed },
+ { "discovery-idle-broken", test_nci_sm_discovery_idle_broken },
+ { "discovery-poll-idle", test_nci_sm_discovery_poll_idle },
+ { "discovery-poll-idle-failed", test_nci_sm_discovery_poll_idle_failed },
+ { "discovery-poll-idle-broken1", test_nci_sm_discovery_poll_idle_broken1 },
+ { "discovery-poll-idle-broken2", test_nci_sm_discovery_poll_idle_broken2 },
+ { "discovery-poll-discovery", test_nci_sm_discovery_poll_discovery },
+ { "discovery-poll-discovery-error1", test_nci_sm_dscvr_poll_dscvr_error1 },
+ { "discovery-poll-discovery-error2", test_nci_sm_dscvr_poll_dscvr_error2 },
+ { "discovery-poll-discovery-error3", test_nci_sm_dscvr_poll_dscvr_error3 },
+ { "discovery-poll-discovery-broken", test_nci_sm_dscvr_poll_dscvr_broken },
+ { "discovery-poll-read-discovery", test_nci_sm_dscvr_poll_read_dscvr },
+ { "discovery-poll-deactivate-t4a", test_nci_sm_dscvr_poll_deact_t4a },
+ { "discovery-poll-activate-error1", test_nci_sm_dscvr_poll_act_error1 },
+ { "discovery-poll-activate-error2", test_nci_sm_dscvr_poll_act_error2 },
+ { "discovery-poll-activate-error3", test_nci_sm_dscvr_poll_act_error3 },
+ { "discovery-poll-activate-error4", test_nci_sm_dscvr_poll_act_error4 },
+ { "discovery-poll-deactivate-t4a-bad-act-param1",
+ test_nci_sm_dscvr_poll_deact_t4a_badparam1 },
+ { "discovery-ntf-t2t", test_nci_sm_discovery_ntf_t2t },
+ { "discovery-ntf-isodep", test_nci_sm_discovery_ntf_isodep }
+};
+
+/*==========================================================================*
+ * Common
+ *==========================================================================*/
+
+#define TEST_PREFIX "/nci_core/"
+#define TEST_(name) TEST_PREFIX name
+
+int main(int argc, char* argv[])
+{
+ guint i;
+
+ g_test_init(&argc, &argv, NULL);
+ g_test_add_func(TEST_("null"), test_null);
+ g_test_add_func(TEST_("restart"), test_restart);
+ g_test_add_func(TEST_("init_ok"), test_init_ok);
+ g_test_add_func(TEST_("init_failed1"), test_init_failed1);
+ g_test_add_func(TEST_("init_failed2"), test_init_failed2);
+ for (i = 0; i < G_N_ELEMENTS(nci_sm_tests); i++) {
+ const TestNciSmData* test = nci_sm_tests + i;
+ char* path = g_strconcat(TEST_PREFIX "sm/", test->name, NULL);
+
+ g_test_add_data_func(path, test, test_nci_sm);
+ g_free(path);
+ }
+ test_init(&test_opt, argc, argv);
+ return g_test_run();
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/unit/nci_sar/Makefile
^
|
@@ -0,0 +1,5 @@
+# -*- Mode: makefile-gmake -*-
+
+EXE = test_nci_sar
+
+include ../common/Makefile
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/unit/nci_sar/test_nci_sar.c
^
|
@@ -0,0 +1,1485 @@
+/*
+ * Copyright (C) 2018-2019 Jolla Ltd.
+ * Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "test_common.h"
+
+#include "nci_types_p.h"
+#include "nci_hal.h"
+#include "nci_sar.h"
+
+#include <gutil_macros.h>
+#include <gutil_log.h>
+
+static TestOpt test_opt;
+
+#define TEST_TIMEOUT (10) /* seconds */
+
+#define TEST_GID (0x01)
+#define TEST_OID (0x02)
+
+static
+gboolean
+test_timeout(
+ gpointer loop)
+{
+ g_assert(!"TIMEOUT");
+ return G_SOURCE_REMOVE;
+}
+
+static
+guint
+test_setup_timeout(
+ GMainLoop* loop)
+{
+ if (!(test_opt.flags & TEST_FLAG_DEBUG)) {
+ return g_timeout_add_seconds(TEST_TIMEOUT, test_timeout, loop);
+ } else {
+ return 0;
+ }
+}
+
+static
+void
+test_bytes_unref(
+ gpointer bytes)
+{
+ g_bytes_unref(bytes);
+}
+
+static
+void
+test_client_unexpected_completion(
+ NciSarClient* client,
+ gboolean success,
+ gpointer user_data)
+{
+ g_assert(FALSE);
+}
+
+static
+void
+test_client_expect_success(
+ NciSarClient* client,
+ gboolean success,
+ gpointer user_data)
+{
+ g_assert(success);
+}
+
+static
+void
+test_client_expect_error(
+ NciSarClient* client,
+ gboolean success,
+ gpointer user_data)
+{
+ g_assert(!success);
+}
+
+static
+void
+test_sar_client_unexpected(
+ NciSarClient* client)
+{
+ g_assert(FALSE);
+}
+
+static
+void
+test_sar_client_unexpected_resp(
+ NciSarClient* client,
+ guint8 gid,
+ guint8 oid,
+ const void* payload,
+ guint payload_len)
+{
+ g_assert(FALSE);
+}
+
+static
+void
+test_sar_client_unexpected_data_packet(
+ NciSarClient* client,
+ guint8 cid,
+ const void* payload,
+ guint payload_len)
+{
+ g_assert(FALSE);
+}
+
+/*==========================================================================*
+ * Test HAL
+ *==========================================================================*/
+
+static
+gboolean
+test_dummy_hal_io_start(
+ NciHalIo* io,
+ NciHalClient* client)
+{
+ return FALSE;
+}
+
+static
+void
+test_dummy_hal_io_stop(
+ NciHalIo* io)
+{
+}
+
+static
+gboolean
+test_dummy_hal_io_write(
+ NciHalIo* io,
+ const GUtilData* chunks,
+ guint count,
+ NciHalClientFunc complete)
+{
+ return FALSE;
+}
+
+static
+void
+test_dummy_hal_io_cancel_write(
+ NciHalIo* io)
+{
+}
+
+static const NciHalIoFunctions test_dummy_hal_io_fn = {
+ .start = test_dummy_hal_io_start,
+ .stop = test_dummy_hal_io_stop,
+ .write = test_dummy_hal_io_write,
+ .cancel_write = test_dummy_hal_io_cancel_write
+};
+
+static NciHalIo test_dummy_hal_io = {
+ .fn = &test_dummy_hal_io_fn
+};
+
+/*==========================================================================*
+ * Test HAL
+ *==========================================================================*/
+
+typedef struct test_hal_io {
+ NciHalIo io;
+ GPtrArray* written;
+ guint write_id;
+ NciHalClient* sar;
+ void* test_data;
+} TestHalIo;
+
+typedef struct test_hal_io_write {
+ TestHalIo* hal;
+ GBytes* bytes;
+ NciHalClientFunc complete;
+} TestHalIoWrite;
+
+static
+void
+test_hal_io_write_free(
+ gpointer user_data)
+{
+ TestHalIoWrite* write = user_data;
+
+ g_bytes_unref(write->bytes);
+ g_free(write);
+}
+
+static
+gboolean
+test_hal_io_write_cb(
+ gpointer user_data)
+{
+ TestHalIoWrite* write = user_data;
+ TestHalIo* hal = write->hal;
+
+ g_assert(hal->write_id);
+ hal->write_id = 0;
+ g_ptr_array_add(hal->written, g_bytes_ref(write->bytes));
+ if (write->complete) {
+ write->complete(hal->sar, TRUE);
+ }
+ return G_SOURCE_REMOVE;
+}
+
+static
+gboolean
+test_hal_io_start(
+ NciHalIo* io,
+ NciHalClient* sar)
+{
+ TestHalIo* hal = G_CAST(io, TestHalIo, io);
+
+ g_assert(!hal->sar);
+ hal->sar = sar;
+ return TRUE;
+}
+
+static
+void
+test_hal_io_stop(
+ NciHalIo* io)
+{
+ TestHalIo* hal = G_CAST(io, TestHalIo, io);
+
+ g_assert(hal->sar);
+ hal->sar = NULL;
+ if (hal->write_id) {
+ g_source_remove(hal->write_id);
+ hal->write_id = 0;
+ }
+}
+
+static
+gboolean
+test_hal_io_write(
+ NciHalIo* io,
+ const GUtilData* chunks,
+ guint count,
+ NciHalClientFunc complete)
+{
+ TestHalIo* hal = G_CAST(io, TestHalIo, io);
+ TestHalIoWrite* write = g_new0(TestHalIoWrite, 1);
+ GByteArray* packet = g_byte_array_new();
+ guint i;
+
+ g_assert(count > 0);
+ for (i = 0; i < count; i++) {
+ g_byte_array_append(packet, chunks[i].bytes, chunks[i].size);
+ }
+
+ g_assert(hal->sar);
+ g_assert(!hal->write_id);
+ write->hal = hal;
+ write->bytes = g_byte_array_free_to_bytes(packet);
+ write->complete = complete;
+ hal->write_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
+ test_hal_io_write_cb, write, test_hal_io_write_free);
+ return TRUE;
+}
+
+static
+void
+test_hal_io_cancel_write(
+ NciHalIo* io)
+{
+ TestHalIo* hal = G_CAST(io, TestHalIo, io);
+
+ g_assert(hal->write_id);
+ g_source_remove(hal->write_id);
+ hal->write_id = 0;
+}
+
+static
+TestHalIo*
+test_hal_io_new_with_functions(
+ const NciHalIoFunctions* fn)
+{
+ TestHalIo* hal = g_new0(TestHalIo, 1);
+
+ hal->io.fn = fn;
+ hal->written = g_ptr_array_new();
+ g_ptr_array_set_free_func(hal->written, test_bytes_unref);
+ return hal;
+}
+
+static
+TestHalIo*
+test_hal_io_new(
+ void)
+{
+ static const NciHalIoFunctions test_hal_io_fn = {
+ .start = test_hal_io_start,
+ .stop = test_hal_io_stop,
+ .write = test_hal_io_write,
+ .cancel_write = test_hal_io_cancel_write
+ };
+
+ return test_hal_io_new_with_functions(&test_hal_io_fn);
+}
+
+static
+void
+test_hal_io_free(
+ TestHalIo* hal)
+{
+ g_assert(!hal->sar);
+ g_assert(!hal->write_id);
+ g_ptr_array_free(hal->written, TRUE);
+ g_free(hal);
+}
+
+/*==========================================================================*
+ * Test SAR client
+ *==========================================================================*/
+
+static
+void
+test_dummy_sar_client_error(
+ NciSarClient* client)
+{
+}
+
+static
+void
+test_dummy_sar_client_handle_response(
+ NciSarClient* client,
+ guint8 gid,
+ guint8 oid,
+ const void* payload,
+ guint payload_len)
+{
+}
+
+static
+void
+test_dummy_sar_client_handle_notification(
+ NciSarClient* client,
+ guint8 gid,
+ guint8 oid,
+ const void* payload,
+ guint payload_len)
+{
+}
+
+static
+void
+test_dummy_sar_client_handle_data_packet(
+ NciSarClient* client,
+ guint8 cid,
+ const void* payload,
+ guint payload_len)
+{
+}
+
+static const NciSarClientFunctions test_dummy_sar_client_fn = {
+ .error = test_dummy_sar_client_error,
+ .handle_response = test_dummy_sar_client_handle_response,
+ .handle_notification = test_dummy_sar_client_handle_notification,
+ .handle_data_packet = test_dummy_sar_client_handle_data_packet
+};
+
+/*==========================================================================*
+ * null
+ *==========================================================================*/
+
+static
+void
+test_null(
+ void)
+{
+ nci_sar_set_max_logical_connections(NULL, 0);
+ nci_sar_set_max_control_packet_size(NULL, 0);
+ g_assert(!nci_sar_send_command(NULL, 0, 0, NULL, NULL, NULL, NULL));
+ g_assert(!nci_sar_send_data_packet(NULL, 0, NULL, NULL, NULL, NULL));
+ g_assert(!nci_sar_start(NULL));
+ nci_sar_set_initial_credits(NULL, 0, 1);
+ nci_sar_add_credits(NULL, 0, 1);
+ nci_sar_reset(NULL);
+ nci_sar_cancel(NULL, 0);
+ nci_sar_free(NULL);
+}
+
+/*==========================================================================*
+ * fail
+ *==========================================================================*/
+
+typedef struct test_fail_client {
+ NciSarClient client;
+ GMainLoop* loop;
+} TestFailClient;
+
+static
+void
+test_fail_expect_error_and_quit(
+ NciSarClient* client,
+ gboolean success,
+ gpointer user_data)
+{
+ TestFailClient* test = G_CAST(client, TestFailClient, client);
+
+ g_assert(!success);
+ g_main_loop_quit(test->loop);
+}
+
+static
+void
+test_fail(
+ void)
+{
+ NciSar* sar;
+ TestFailClient test;
+ guint timeout_id;
+
+ memset(&test, 0, sizeof(test));
+ test.client.fn = &test_dummy_sar_client_fn;
+
+ sar = nci_sar_new(&test_dummy_hal_io, &test.client);
+ nci_sar_set_initial_credits(sar, 0, 1);
+ g_assert(nci_sar_send_command(sar, 0, 0, NULL, NULL, NULL, NULL));
+ g_assert(nci_sar_send_command(sar, 0, 0, NULL,
+ test_client_expect_error, NULL, NULL));
+ g_assert(nci_sar_send_data_packet(sar, 0, NULL,
+ test_fail_expect_error_and_quit, NULL, NULL));
+ nci_sar_cancel(sar, 0); /* Does nothing */
+ nci_sar_cancel(sar, 112345); /* Invalid ID */
+
+ test.loop = g_main_loop_new(NULL, TRUE);
+ timeout_id = test_setup_timeout(test.loop);
+ g_main_loop_run(test.loop);
+ if (timeout_id) {
+ g_source_remove(timeout_id);
+ }
+
+ nci_sar_free(sar);
+ g_main_loop_unref(test.loop);
+}
+
+/*==========================================================================*
+ * basic
+ *==========================================================================*/
+
+typedef struct test_basic_client {
+ NciSarClient client;
+ int error_count;
+ GMainLoop* loop;
+} TestBasicClient;
+
+static
+void
+test_basic_sar_client_error(
+ NciSarClient* client)
+{
+ G_CAST(client, TestBasicClient, client)->error_count++;
+}
+
+static
+void
+test_basic_expect_success_and_quit(
+ NciSarClient* client,
+ gboolean success,
+ gpointer user_data)
+{
+ TestBasicClient* test = G_CAST(client, TestBasicClient, client);
+
+ g_assert(success);
+ g_main_loop_quit(test->loop);
+}
+
+static
+void
+test_basic(
+ void)
+{
+ static const NciSarClientFunctions test_basic_sar_client_fn = {
+ .error = test_basic_sar_client_error,
+ .handle_response = test_dummy_sar_client_handle_response,
+ .handle_notification = test_dummy_sar_client_handle_notification,
+ .handle_data_packet = test_dummy_sar_client_handle_data_packet
+ };
+
+ NciSar* sar;
+ TestHalIo* test_io = test_hal_io_new();
+ TestBasicClient test;
+ guint timeout_id;
+
+ memset(&test, 0, sizeof(test));
+ test.client.fn = &test_basic_sar_client_fn;
+
+ sar = nci_sar_new(&test_io->io, &test.client);
+ nci_sar_set_max_logical_connections(sar, 0);
+ nci_sar_set_max_logical_connections(sar, 1);
+ nci_sar_set_max_logical_connections(sar, 3);
+ nci_sar_set_max_logical_connections(sar, 2);
+ nci_sar_set_max_control_packet_size(sar, 0);
+ nci_sar_set_max_control_packet_size(sar, 0xff);
+ nci_sar_set_initial_credits(sar, 42, 1); /* Invalid cid */
+ nci_sar_set_initial_credits(sar, 0, 0xfe);
+ nci_sar_add_credits(sar, 0, 1);
+ nci_sar_add_credits(sar, 0, 1); /* one too many */
+ g_assert(nci_sar_send_command(sar, TEST_GID, TEST_OID, NULL,
+ NULL, NULL, NULL));
+ g_assert(nci_sar_send_command(sar, TEST_GID, TEST_OID, NULL,
+ test_client_expect_success, NULL, NULL));
+ g_assert(nci_sar_send_data_packet(sar, 0, NULL,
+ test_basic_expect_success_and_quit, NULL, NULL));
+ nci_sar_add_credits(sar, 0, 1); /* No effect */
+ nci_sar_add_credits(sar, 42, 1); /* Invalid cid */
+
+ test.loop = g_main_loop_new(NULL, TRUE);
+ timeout_id = test_setup_timeout(test.loop);
+ g_main_loop_run(test.loop);
+
+ /* Signal error */
+ g_assert(test_io->sar);
+ test_io->sar->fn->error(test_io->sar);
+ g_assert(test.error_count == 1);
+ nci_sar_reset(sar);
+
+ g_assert(test_io->written->len == 3);
+ if (timeout_id) {
+ g_source_remove(timeout_id);
+ }
+
+ nci_sar_free(sar);
+ test_hal_io_free(test_io);
+ g_main_loop_unref(test.loop);
+}
+
+/*==========================================================================*
+ * send_seg
+ *==========================================================================*/
+
+typedef struct test_send_seg_data {
+ NciSarClient client;
+ NciSar* sar;
+ int error_count;
+ GMainLoop* loop;
+ guint send_id;
+} TestSendSegData;
+
+static
+void
+test_send_seg_expect_success_and_quit(
+ NciSarClient* client,
+ gboolean success,
+ gpointer user_data)
+{
+ TestSendSegData* test = G_CAST(client, TestSendSegData, client);
+
+ g_assert(success);
+ g_main_loop_quit(test->loop);
+}
+
+static
+gboolean
+test_send_seg_hal_io_write(
+ NciHalIo* io,
+ const GUtilData* chunks,
+ guint count,
+ NciHalClientFunc complete)
+{
+ TestHalIo* hal = G_CAST(io, TestHalIo, io);
+ TestSendSegData* test = hal->test_data;
+
+ g_assert(test_hal_io_write(io, chunks, count, complete));
+
+ /* Both packets will still be sent (because we cancel this one after
+ * we have already started writing it), it's just that the completion
+ * callback won't be invoked for the first packet. Note that we call
+ * cancel many times, but only the first time it really does something. */
+ nci_sar_cancel(test->sar, test->send_id);
+ return TRUE;
+}
+
+static
+void
+test_send_seg(
+ void)
+{
+ static const NciHalIoFunctions hal_io_fn = {
+ .start = test_hal_io_start,
+ .stop = test_hal_io_stop,
+ .write = test_send_seg_hal_io_write,
+ .cancel_write = test_hal_io_cancel_write
+ };
+
+ /* Set MTU to minimum and send one byte of payload per packet */
+ static const guint8 payload[] = { 0x01, 0x02 };
+ GBytes* payload_bytes = g_bytes_new_static(payload, sizeof(payload));
+ TestHalIo* test_io = test_hal_io_new_with_functions(&hal_io_fn);
+ TestSendSegData test;
+ guint timeout_id, i;
+
+ memset(&test, 0, sizeof(test));
+ test.client.fn = &test_dummy_sar_client_fn;
+ test_io->test_data = &test;
+
+ test.sar = nci_sar_new(&test_io->io, &test.client);
+ nci_sar_set_max_control_packet_size(test.sar, 3); /* Actually sets 4 */
+ test.send_id = nci_sar_send_command(test.sar, TEST_GID, TEST_OID,
+ payload_bytes, test_client_unexpected_completion, NULL, NULL);
+ g_assert(test.send_id);
+ g_assert(nci_sar_send_command(test.sar, TEST_GID, TEST_OID,
+ payload_bytes, test_send_seg_expect_success_and_quit, NULL, NULL));
+
+ test.loop = g_main_loop_new(NULL, TRUE);
+ timeout_id = test_setup_timeout(test.loop);
+ g_main_loop_run(test.loop);
+
+ /* The same data have been sent twice */
+ g_assert(test_io->written->len == 2*sizeof(payload));
+ for (i = 0; i < test_io->written->len; i++) {
+ GBytes* packet = test_io->written->pdata[i];
+ gsize packet_size;
+ const guint8* packet_data = g_bytes_get_data(packet, &packet_size);
+
+ g_assert(packet_size == 4);
+ g_assert(packet_data[3] == payload[i % sizeof(payload)]);
+
+ }
+ if (timeout_id) {
+ g_source_remove(timeout_id);
+ }
+
+ nci_sar_free(test.sar);
+ test_hal_io_free(test_io);
+ g_main_loop_unref(test.loop);
+ g_bytes_unref(payload_bytes);
+}
+
+/*==========================================================================*
+ * send_err
+ *==========================================================================*/
+
+typedef struct test_send_err_hal_io {
+ NciHalIo io;
+ NciHalClient* sar;
+} TestSendErrHalIo;
+
+typedef struct test_send_err_hal_io_write {
+ NciHalClient* sar;
+ NciHalClientFunc complete;
+} TestSendErrHalIoWrite;
+
+static
+gboolean
+test_send_err_hal_io_start(
+ NciHalIo* io,
+ NciHalClient* sar)
+{
+ TestSendErrHalIo* hal = G_CAST(io, TestSendErrHalIo, io);
+
+ g_assert(!hal->sar);
+ hal->sar = sar;
+ return TRUE;
+}
+
+static
+gboolean
+test_send_err_hal_io_write_cb(
+ gpointer user_data)
+{
+ TestSendErrHalIoWrite* write = user_data;
+
+ write->complete(write->sar, FALSE);
+ return G_SOURCE_REMOVE;
+}
+
+static
+gboolean
+test_send_err_hal_io_write(
+ NciHalIo* io,
+ const GUtilData* chunks,
+ guint count,
+ NciHalClientFunc complete)
+{
+ TestSendErrHalIo* hal = G_CAST(io, TestSendErrHalIo, io);
+ TestSendErrHalIoWrite* write = g_new0(TestSendErrHalIoWrite, 1);
+
+ write->complete = complete;
+ write->sar = hal->sar;
+ g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, test_send_err_hal_io_write_cb,
+ write, g_free);
+ return TRUE;
+}
+
+static
+TestSendErrHalIo*
+test_send_err_hal_io_new(
+ void)
+{
+ static const NciHalIoFunctions test_dummy_hal_io_fn = {
+ .start = test_send_err_hal_io_start,
+ .stop = test_dummy_hal_io_stop,
+ .write = test_send_err_hal_io_write,
+ .cancel_write = test_dummy_hal_io_cancel_write
+ };
+ TestSendErrHalIo* hal = g_new0(TestSendErrHalIo, 1);
+
+ hal->io.fn = &test_dummy_hal_io_fn;
+ return hal;
+}
+
+static
+void
+test_send_err_hal_io(
+ TestSendErrHalIo* hal)
+{
+ g_free(hal);
+}
+
+typedef struct test_send_err_sar_client {
+ NciSarClient client;
+ GMainLoop* loop;
+ gboolean completed;
+} TestSendErrSarClient;
+
+static
+void
+test_send_err_sar_send_complete(
+ NciSarClient* client,
+ gboolean success,
+ gpointer user_data)
+{
+ TestSendErrSarClient* test = user_data;
+
+ g_assert(&test->client == client);
+ g_assert(!success);
+ g_assert(!test->completed);
+ test->completed = TRUE;
+}
+
+static
+void
+test_send_err_sar_client_error(
+ NciSarClient* client)
+{
+ TestSendErrSarClient* test = G_CAST(client, TestSendErrSarClient, client);
+
+ g_main_loop_quit(test->loop);
+}
+
+static
+void
+test_send_err(
+ void)
+{
+ static const NciSarClientFunctions test_send_err_sar_client_fn = {
+ .error = test_send_err_sar_client_error,
+ .handle_response = test_dummy_sar_client_handle_response,
+ .handle_notification = test_dummy_sar_client_handle_notification,
+ .handle_data_packet = test_dummy_sar_client_handle_data_packet
+ };
+ TestSendErrHalIo* test_io = test_send_err_hal_io_new();
+ TestSendErrSarClient test;
+ NciSar* sar;
+ guint timeout_id;
+
+ memset(&test, 0, sizeof(test));
+ test.client.fn = &test_send_err_sar_client_fn;
+ test.loop = g_main_loop_new(NULL, TRUE);
+ timeout_id = test_setup_timeout(test.loop);
+
+ sar = nci_sar_new(&test_io->io, &test.client);
+ g_assert(nci_sar_start(sar));
+ g_assert(test_io->sar);
+
+ /* This send fails asynchronously */
+ g_assert(nci_sar_send_command(sar, TEST_GID, TEST_OID, NULL,
+ NULL, NULL, NULL));
+
+ g_main_loop_run(test.loop);
+
+ /* Same thing but with a completion callback */
+ g_assert(nci_sar_send_command(sar, TEST_GID, TEST_OID, NULL,
+ test_send_err_sar_send_complete, NULL, &test));
+
+ g_main_loop_run(test.loop);
+ if (timeout_id) {
+ g_source_remove(timeout_id);
+ }
+
+ nci_sar_free(sar);
+ test_send_err_hal_io(test_io);
+ g_main_loop_unref(test.loop);
+}
+
+/*==========================================================================*
+ * recv_ntf
+ *==========================================================================*/
+
+typedef struct test_recv_ntf {
+ NciSarClient client;
+ int ntf_received;
+} TestRecvNtf;
+
+static
+void
+test_recv_ntf_handle(
+ NciSarClient* client,
+ guint8 gid,
+ guint8 oid,
+ const void* payload,
+ guint payload_len)
+{
+ TestRecvNtf* test = G_CAST(client, TestRecvNtf, client);
+
+ g_assert(gid == TEST_GID);
+ g_assert(oid == TEST_OID);
+ g_assert(!payload_len);
+ test->ntf_received++;
+}
+
+static
+void
+test_recv_ntf(
+ void)
+{
+ static const NciSarClientFunctions test_recv_ntf_sar_client_fn = {
+ .error = test_dummy_sar_client_error,
+ .handle_response = test_dummy_sar_client_handle_response,
+ .handle_notification = test_recv_ntf_handle,
+ .handle_data_packet = test_dummy_sar_client_handle_data_packet
+ };
+ static const guint8 ntf[] = { NCI_MT_NTF_PKT | TEST_GID, TEST_OID, 0 };
+ NciSar* sar;
+ TestHalIo* test_io = test_hal_io_new();
+ TestRecvNtf test;
+
+ memset(&test, 0, sizeof(test));
+ test.client.fn = &test_recv_ntf_sar_client_fn;
+
+ sar = nci_sar_new(&test_io->io, &test.client);
+ g_assert(nci_sar_start(sar));
+ g_assert(nci_sar_start(sar)); /* Double start is handled */
+ g_assert(test_io->sar);
+
+ /* Test reception of a complete (non-segmented) packet */
+ test_io->sar->fn->read(test_io->sar, ntf, sizeof(ntf));
+ g_assert(test.ntf_received == 1);
+
+ nci_sar_free(sar);
+ test_hal_io_free(test_io);
+}
+
+/*==========================================================================*
+ * recv_ntf_data
+ *==========================================================================*/
+
+typedef struct test_recv_ntf_data {
+ NciSarClient client;
+ int ntf_received;
+} TestRecvNtfData;
+
+static const guint8 test_recv_ntf_data_payload[] = { 0x01, 0x02, 0x03 };
+
+static
+void
+test_recv_ntf_data_handle(
+ NciSarClient* client,
+ guint8 gid,
+ guint8 oid,
+ const void* payload,
+ guint payload_len)
+{
+ TestRecvNtfData* test = G_CAST(client, TestRecvNtfData, client);
+
+ g_assert(gid == TEST_GID);
+ g_assert(oid == TEST_OID);
+ g_assert(payload_len == sizeof(test_recv_ntf_data_payload));
+ g_assert(!memcmp(test_recv_ntf_data_payload, payload, payload_len));
+ test->ntf_received++;
+}
+
+static
+void
+test_recv_ntf_data(
+ void)
+{
+ static const NciSarClientFunctions test_recv_ntf_sar_client_fn = {
+ .error = test_dummy_sar_client_error,
+ .handle_response = test_dummy_sar_client_handle_response,
+ .handle_notification = test_recv_ntf_data_handle,
+ .handle_data_packet = test_dummy_sar_client_handle_data_packet
+ };
+ static const guint8 hdr[] = { NCI_MT_NTF_PKT | TEST_GID, TEST_OID };
+ NciSar* sar;
+ TestHalIo* test_io = test_hal_io_new();
+ GByteArray* packet = g_byte_array_new();
+ TestRecvNtfData test;
+ guint8 payload_len = sizeof(test_recv_ntf_data_payload);
+
+ g_byte_array_append(packet, hdr, sizeof(hdr));
+ g_byte_array_append(packet, &payload_len, 1);
+ g_byte_array_append(packet, test_recv_ntf_data_payload,
+ sizeof(test_recv_ntf_data_payload));
+
+ memset(&test, 0, sizeof(test));
+ test.client.fn = &test_recv_ntf_sar_client_fn;
+
+ sar = nci_sar_new(&test_io->io, &test.client);
+ g_assert(nci_sar_start(sar));
+ g_assert(test_io->sar);
+
+ /* Test reception of a complete (non-segmented) packet */
+ test_io->sar->fn->read(test_io->sar, packet->data, packet->len);
+ g_assert(test.ntf_received == 1);
+
+ nci_sar_free(sar);
+ test_hal_io_free(test_io);
+ g_byte_array_free(packet, TRUE);
+}
+
+/*==========================================================================*
+ * recv_multi
+ *==========================================================================*/
+
+typedef struct test_recv_multi {
+ NciSarClient client;
+ int ntf_received;
+ int rsp_received;
+} TestRecvMulti;
+
+static
+void
+test_recv_multi_handle_resp(
+ NciSarClient* client,
+ guint8 gid,
+ guint8 oid,
+ const void* payload,
+ guint payload_len)
+{
+ TestRecvMulti* test = G_CAST(client, TestRecvMulti, client);
+
+ g_assert(gid == TEST_GID);
+ g_assert(oid == TEST_OID);
+ g_assert(!payload_len);
+ test->rsp_received++;
+}
+
+static
+void
+test_recv_multi_handle_ntf(
+ NciSarClient* client,
+ guint8 gid,
+ guint8 oid,
+ const void* payload,
+ guint payload_len)
+{
+ TestRecvMulti* test = G_CAST(client, TestRecvMulti, client);
+
+ g_assert(gid == TEST_GID);
+ g_assert(oid == TEST_OID);
+ g_assert(!payload_len);
+ test->ntf_received++;
+}
+
+static
+void
+test_recv_multi(
+ void)
+{
+ static const NciSarClientFunctions test_recv_multi_fn = {
+ .error = test_dummy_sar_client_error,
+ .handle_response = test_recv_multi_handle_resp,
+ .handle_notification = test_recv_multi_handle_ntf,
+ .handle_data_packet = test_dummy_sar_client_handle_data_packet
+ };
+ static const guint8 packets[] = {
+ NCI_MT_RSP_PKT | TEST_GID, TEST_OID, 0,
+ NCI_MT_NTF_PKT | TEST_GID, TEST_OID, 0,
+ NCI_MT_CMD_PKT | TEST_GID, TEST_OID, 0 /* This one is ignored */
+ };
+ NciSar* sar;
+ TestHalIo* test_io = test_hal_io_new();
+ TestRecvMulti test;
+
+ memset(&test, 0, sizeof(test));
+ test.client.fn = &test_recv_multi_fn;
+
+ sar = nci_sar_new(&test_io->io, &test.client);
+ g_assert(nci_sar_start(sar));
+ g_assert(test_io->sar);
+
+ test_io->sar->fn->read(test_io->sar, packets, sizeof(packets));
+ g_assert(test.ntf_received == 1);
+ g_assert(test.rsp_received == 1);
+
+ nci_sar_free(sar);
+ test_hal_io_free(test_io);
+}
+
+/*==========================================================================*
+ * recv_seg
+ *==========================================================================*/
+
+typedef struct test_recv_seg {
+ NciSarClient client;
+ int ntf_received;
+ int rsp_received;
+} TestRecvSeg;
+
+static
+void
+test_recv_seg_handle_resp(
+ NciSarClient* client,
+ guint8 gid,
+ guint8 oid,
+ const void* payload,
+ guint payload_len)
+{
+ TestRecvSeg* test = G_CAST(client, TestRecvSeg, client);
+
+ g_assert(gid == TEST_GID);
+ g_assert(oid == TEST_OID);
+ g_assert(!payload_len);
+ test->rsp_received++;
+}
+
+static
+void
+test_recv_seg_handle_ntf(
+ NciSarClient* client,
+ guint8 gid,
+ guint8 oid,
+ const void* payload,
+ guint payload_len)
+{
+ TestRecvSeg* test = G_CAST(client, TestRecvSeg, client);
+ static const guint8 expected_data[] = { 0x01, 0x02, 0x03 };
+
+ g_assert(gid == TEST_GID);
+ g_assert(oid == TEST_OID);
+ g_assert(payload_len == sizeof(expected_data));
+ g_assert(!memcmp(expected_data, payload, payload_len));
+ test->ntf_received++;
+}
+
+static
+void
+test_recv_seg(
+ void)
+{
+ static const NciSarClientFunctions test_recv_seg_fn = {
+ .error = test_sar_client_unexpected,
+ .handle_response = test_recv_seg_handle_resp,
+ .handle_notification = test_recv_seg_handle_ntf,
+ .handle_data_packet = test_sar_client_unexpected_data_packet
+ };
+ static const guint8 buf1[] = {
+ NCI_MT_RSP_PKT | TEST_GID, TEST_OID,
+ };
+ static const guint8 buf2[] = {
+ 0, /* End of the first packet */
+ NCI_MT_NTF_PKT | TEST_GID | NCI_PBF, TEST_OID, 1, 0x01
+ };
+ static const guint8 buf3[] = {
+ NCI_MT_NTF_PKT | TEST_GID, TEST_OID, 2, 0x02
+ };
+ static const guint8 buf4[] = {
+ 0x03 /* End of the third packet */
+ };
+ NciSar* sar;
+ TestHalIo* test_io = test_hal_io_new();
+ TestRecvSeg test;
+
+ memset(&test, 0, sizeof(test));
+ test.client.fn = &test_recv_seg_fn;
+
+ sar = nci_sar_new(&test_io->io, &test.client);
+ g_assert(nci_sar_start(sar));
+ g_assert(test_io->sar);
+
+ test_io->sar->fn->read(test_io->sar, buf1, sizeof(buf1));
+ test_io->sar->fn->read(test_io->sar, buf2, sizeof(buf2));
+ test_io->sar->fn->read(test_io->sar, buf3, sizeof(buf3));
+ test_io->sar->fn->read(test_io->sar, buf4, sizeof(buf4));
+ g_assert(test.ntf_received == 1);
+ g_assert(test.rsp_received == 1);
+
+ nci_sar_free(sar);
+ test_hal_io_free(test_io);
+}
+
+/*==========================================================================*
+ * recv_seg_err
+ *==========================================================================*/
+
+typedef struct test_recv_seg_err {
+ NciSarClient client;
+ gboolean error;
+} TestRecvSegErr;
+
+static
+void
+test_recv_seg_err_client_error(
+ NciSarClient* client)
+{
+ TestRecvSegErr* test = G_CAST(client, TestRecvSegErr, client);
+
+ test->error = TRUE;
+}
+
+static
+void
+test_recv_seg_err(
+ void)
+{
+ static const NciSarClientFunctions test_recv_seg_err_fn = {
+ .error = test_recv_seg_err_client_error,
+ .handle_response = test_sar_client_unexpected_resp,
+ .handle_notification = test_sar_client_unexpected_resp,
+ .handle_data_packet = test_sar_client_unexpected_data_packet
+ };
+ static const guint8 buf1[] = {
+ NCI_MT_NTF_PKT | TEST_GID | NCI_PBF, TEST_OID, 1, 0x01
+ };
+ static const guint8 buf2[] = {
+ NCI_MT_RSP_PKT | TEST_GID, TEST_OID, 2, 0x02, 0x03
+ };
+ static const guint8 buf3[] = {
+ NCI_MT_NTF_PKT | (TEST_GID + 1), TEST_OID, 2, 0x02, 0x03
+ };
+ static const guint8 buf4[] = {
+ NCI_MT_NTF_PKT | TEST_GID, TEST_OID + 1, 2, 0x02, 0x03
+ };
+
+ NciSar* sar;
+ TestHalIo* test_io = test_hal_io_new();
+ TestRecvSegErr test;
+
+ memset(&test, 0, sizeof(test));
+ test.client.fn = &test_recv_seg_err_fn;
+
+ sar = nci_sar_new(&test_io->io, &test.client);
+ g_assert(nci_sar_start(sar));
+ g_assert(test_io->sar);
+
+ test_io->sar->fn->read(test_io->sar, buf1, sizeof(buf1));
+ g_assert(!test.error);
+
+ /* Packet type mismatch */
+ test_io->sar->fn->read(test_io->sar, buf2, sizeof(buf2));
+ g_assert(test.error);
+
+ /* GID mismatch */
+ test.error = FALSE;
+ test_io->sar->fn->read(test_io->sar, buf3, sizeof(buf3));
+ g_assert(test.error);
+
+ /* OID mismatch */
+ test.error = FALSE;
+ test_io->sar->fn->read(test_io->sar, buf4, sizeof(buf4));
+ g_assert(test.error);
+
+ nci_sar_free(sar);
+ test_hal_io_free(test_io);
+}
+
+/*==========================================================================*
+ * bad_cid
+ *==========================================================================*/
+
+typedef struct test_error_count {
+ NciSarClient client;
+ int error_count;
+} TestErrorCount;
+
+static
+void
+test_sar_client_error_count(
+ NciSarClient* client)
+{
+ TestErrorCount* test = G_CAST(client, TestErrorCount, client);
+
+ test->error_count++;
+}
+
+static
+void
+test_bad_cid(
+ void)
+{
+ static const NciSarClientFunctions test_bad_cid_fn = {
+ .error = test_sar_client_error_count,
+ .handle_response = test_sar_client_unexpected_resp,
+ .handle_notification = test_sar_client_unexpected_resp,
+ .handle_data_packet = test_sar_client_unexpected_data_packet
+ };
+ static const guint8 buf[] = {
+ NCI_MT_DATA_PKT | 1, 0, 0, 0
+ };
+ NciSar* sar;
+ TestHalIo* test_io = test_hal_io_new();
+ TestErrorCount test;
+
+ memset(&test, 0, sizeof(test));
+ test.client.fn = &test_bad_cid_fn;
+
+ sar = nci_sar_new(&test_io->io, &test.client);
+ g_assert(nci_sar_start(sar));
+ g_assert(test_io->sar);
+
+ nci_sar_set_max_logical_connections(sar, 1);
+ test_io->sar->fn->read(test_io->sar, buf, sizeof(buf));
+ g_assert(test.error_count == 1);
+
+ nci_sar_free(sar);
+ test_hal_io_free(test_io);
+}
+
+/*==========================================================================*
+ * recv_data
+ *==========================================================================*/
+
+typedef struct test_recv_data {
+ NciSarClient client;
+ int packet_count;
+} TestRecvData;
+
+static
+void
+test_recv_data_handle_packet(
+ NciSarClient* client,
+ guint8 cid,
+ const void* payload,
+ guint payload_len)
+{
+ TestRecvData* test = G_CAST(client, TestRecvData, client);
+ static const guint8 payload1[] = { 0x01 };
+ static const guint8 payload2[] = { 0x02, 0x03 };
+
+ GDEBUG("packet #%d, %u byte(s)", test->packet_count, payload_len);
+ switch (test->packet_count) {
+ case 0:
+ g_assert(cid == 0);
+ g_assert(payload_len == 0);
+ break;
+ case 1:
+ g_assert(cid == 1);
+ g_assert(payload_len == sizeof(payload1));
+ g_assert(!memcmp(payload, payload1, payload_len));
+ break;
+ case 2:
+ g_assert(cid == 1);
+ g_assert(payload_len == sizeof(payload2));
+ g_assert(!memcmp(payload, payload2, payload_len));
+ break;
+ default: g_assert(FALSE);
+ }
+ test->packet_count++;
+}
+
+static
+void
+test_recv_data(
+ void)
+{
+ static const NciSarClientFunctions test_recv_data_fn = {
+ .error = test_dummy_sar_client_error,
+ .handle_response = test_sar_client_unexpected_resp,
+ .handle_notification = test_sar_client_unexpected_resp,
+ .handle_data_packet = test_recv_data_handle_packet
+ };
+ static const guint8 buf1[] = {
+ NCI_MT_DATA_PKT, 0,
+ };
+ static const guint8 buf2[] = {
+ 0, /* End of the first packet */
+ NCI_MT_DATA_PKT | 1, 0, 1, 0x01
+ };
+ static const guint8 buf3[] = {
+ NCI_MT_DATA_PKT | 1, 0, 2, 0x02
+ };
+ static const guint8 buf4[] = {
+ 0x03 /* End of the third packet */
+ };
+ NciSar* sar;
+ TestHalIo* test_io = test_hal_io_new();
+ TestRecvData test;
+
+ memset(&test, 0, sizeof(test));
+ test.client.fn = &test_recv_data_fn;
+
+ sar = nci_sar_new(&test_io->io, &test.client);
+ g_assert(nci_sar_start(sar));
+ g_assert(test_io->sar);
+
+ nci_sar_set_max_logical_connections(sar, 2);
+ test_io->sar->fn->read(test_io->sar, buf1, sizeof(buf1));
+ test_io->sar->fn->read(test_io->sar, buf2, sizeof(buf2));
+ test_io->sar->fn->read(test_io->sar, buf3, sizeof(buf3));
+ test_io->sar->fn->read(test_io->sar, buf4, sizeof(buf4));
+ g_assert(test.packet_count == 3);
+
+ nci_sar_free(sar);
+ test_hal_io_free(test_io);
+}
+
+/*==========================================================================*
+ * recv_data_seg
+ *==========================================================================*/
+
+typedef struct test_recv_data_seg {
+ NciSarClient client;
+ gboolean packet_received;
+} TestRecvDataSeg;
+
+static
+void
+test_recv_data_seg_handle_packet(
+ NciSarClient* client,
+ guint8 cid,
+ const void* payload,
+ guint payload_len)
+{
+ TestRecvDataSeg* test = G_CAST(client, TestRecvDataSeg, client);
+ static const guint8 expected_payload[] = { 0x01, 0x02, 0x03 };
+
+ g_assert(cid == 1);
+ g_assert(payload_len == sizeof(expected_payload));
+ g_assert(!memcmp(payload, expected_payload, payload_len));
+ g_assert(!test->packet_received);
+ test->packet_received = TRUE;
+}
+
+static
+void
+test_recv_data_seg(
+ void)
+{
+ static const NciSarClientFunctions test_recv_data_seg_fn = {
+ .error = test_dummy_sar_client_error,
+ .handle_response = test_sar_client_unexpected_resp,
+ .handle_notification = test_sar_client_unexpected_resp,
+ .handle_data_packet = test_recv_data_seg_handle_packet
+ };
+ static const guint8 buf1[] = {
+ NCI_MT_DATA_PKT | NCI_PBF | 1, 0,
+ };
+ static const guint8 buf2[] = {
+ 1, 0x01, /* End of the first packet */
+ NCI_MT_DATA_PKT | NCI_PBF | 1, 0, 1, 0x02
+ };
+ static const guint8 buf3[] = {
+ NCI_MT_DATA_PKT | 1, 0, 1
+ };
+ static const guint8 buf4[] = {
+ 0x03 /* End of the complete packet */
+ };
+ NciSar* sar;
+ TestHalIo* test_io = test_hal_io_new();
+ TestRecvDataSeg test;
+
+ memset(&test, 0, sizeof(test));
+ test.client.fn = &test_recv_data_seg_fn;
+
+ sar = nci_sar_new(&test_io->io, &test.client);
+ g_assert(nci_sar_start(sar));
+ g_assert(test_io->sar);
+
+ nci_sar_set_max_logical_connections(sar, 2);
+ test_io->sar->fn->read(test_io->sar, buf1, sizeof(buf1));
+ test_io->sar->fn->read(test_io->sar, buf2, sizeof(buf2));
+ test_io->sar->fn->read(test_io->sar, buf3, sizeof(buf3));
+ test_io->sar->fn->read(test_io->sar, buf4, sizeof(buf4));
+ g_assert(test.packet_received);
+ nci_sar_set_max_logical_connections(sar, 1);
+
+ nci_sar_free(sar);
+ test_hal_io_free(test_io);
+}
+
+/*==========================================================================*
+ * recv_reset
+ *==========================================================================*/
+
+static
+void
+test_reset(
+ void)
+{
+ static const NciSarClientFunctions test_reset_fn = {
+ .error = test_sar_client_unexpected,
+ .handle_response = test_sar_client_unexpected_resp,
+ .handle_notification = test_sar_client_unexpected_resp,
+ .handle_data_packet = test_sar_client_unexpected_data_packet
+ };
+ static const guint8 buf1[] = {
+ NCI_MT_DATA_PKT | NCI_PBF | 1, 0, 1, 0x02
+ };
+ NciSar* sar;
+ TestHalIo* test_io = test_hal_io_new();
+ NciSarClient client;
+
+ memset(&client, 0, sizeof(client));
+ client.fn = &test_reset_fn;
+
+ sar = nci_sar_new(&test_io->io, &client);
+ g_assert(nci_sar_start(sar));
+ g_assert(test_io->sar);
+
+ nci_sar_set_max_logical_connections(sar, 2);
+ test_io->sar->fn->read(test_io->sar, buf1, sizeof(buf1));
+ g_assert(nci_sar_send_command(sar, TEST_GID, TEST_OID, NULL,
+ test_client_unexpected_completion, NULL, NULL));
+ nci_sar_reset(sar);
+
+ nci_sar_cancel(sar, nci_sar_send_command(sar, TEST_GID, TEST_OID, NULL,
+ test_client_unexpected_completion, NULL, NULL));
+ nci_sar_reset(sar);
+
+ g_assert(nci_sar_send_command(sar, TEST_GID, TEST_OID, NULL,
+ test_client_unexpected_completion, NULL, NULL));
+ nci_sar_cancel(sar, nci_sar_send_command(sar, TEST_GID, TEST_OID, NULL,
+ test_client_unexpected_completion, NULL, NULL));
+ nci_sar_reset(sar);
+
+ nci_sar_free(sar);
+ test_hal_io_free(test_io);
+}
+
+/*==========================================================================*
+ * Common
+ *==========================================================================*/
+
+#define TEST_(name) "/nci_sar/" name
+
+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_("fail"), test_fail);
+ g_test_add_func(TEST_("basic"), test_basic);
+ g_test_add_func(TEST_("send_seg"), test_send_seg);
+ g_test_add_func(TEST_("send_err"), test_send_err);
+ g_test_add_func(TEST_("recv_ntf"), test_recv_ntf);
+ g_test_add_func(TEST_("recv_ntf_data"), test_recv_ntf_data);
+ g_test_add_func(TEST_("recv_multi"), test_recv_multi);
+ g_test_add_func(TEST_("recv_seg"), test_recv_seg);
+ g_test_add_func(TEST_("recv_seg_err"), test_recv_seg_err);
+ g_test_add_func(TEST_("bad_cid"), test_bad_cid);
+ g_test_add_func(TEST_("recv_data"), test_recv_data);
+ g_test_add_func(TEST_("recv_data_seg"), test_recv_data_seg);
+ g_test_add_func(TEST_("recv_reset"), test_reset);
+ test_init(&test_opt, argc, argv);
+ return g_test_run();
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/unit/nci_sm/Makefile
^
|
@@ -0,0 +1,5 @@
+# -*- Mode: makefile-gmake -*-
+
+EXE = test_nci_sm
+
+include ../common/Makefile
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/unit/nci_sm/test_nci_sm.c
^
|
@@ -0,0 +1,578 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "test_common.h"
+
+#include "nci_types_p.h"
+#include "nci_sm.h"
+#include "nci_state.h"
+#include "nci_state_p.h"
+#include "nci_state_impl.h"
+#include "nci_transition_impl.h"
+#include "nci_param_w4_all_discoveries.h"
+
+static TestOpt test_opt;
+
+static
+void
+test_count_cb(
+ NciSm* sm,
+ void* user_data)
+{
+ (*((int*)user_data))++;
+}
+
+static
+void
+test_unreached_cb(
+ NciSm* sm,
+ void* user_data)
+{
+ g_assert(FALSE);
+}
+
+/*==========================================================================*
+ * Test state
+ *==========================================================================*/
+
+typedef NciStateClass TestStateClass;
+typedef struct test_state {
+ NciState state;
+ int entered;
+ int reentered;
+ int left;
+} TestState;
+
+G_DEFINE_TYPE(TestState, test_state, NCI_TYPE_STATE)
+#define TEST_STATE_OBJ(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ TEST_TYPE_STATE, TestState))
+#define TEST_TYPE_STATE (test_state_get_type())
+#define TEST_STATE_PARENT (test_state_parent_class)
+#define TEST_STATE NCI_CORE_STATES
+#define INVALID_STATE (TEST_STATE + 1)
+
+static
+void
+test_state_enter(
+ NciState* state,
+ NciParam* param)
+{
+ TEST_STATE_OBJ(state)->entered++;
+ NCI_STATE_CLASS(test_state_parent_class)->enter(state, param);
+}
+
+static
+void
+test_state_reenter(
+ NciState* state,
+ NciParam* param)
+{
+ TEST_STATE_OBJ(state)->reentered++;
+ NCI_STATE_CLASS(test_state_parent_class)->reenter(state, param);
+}
+
+static
+void
+test_state_leave(
+ NciState* state)
+{
+ TEST_STATE_OBJ(state)->left++;
+ NCI_STATE_CLASS(test_state_parent_class)->leave(state);
+}
+
+static
+void
+test_state_init(
+ TestState* self)
+{
+}
+
+static
+void
+test_state_class_init(
+ TestStateClass* klass)
+{
+ klass->enter = test_state_enter;
+ klass->reenter = test_state_reenter;
+ klass->leave = test_state_leave;
+}
+
+TestState*
+test_state_new(
+ NciSm* sm,
+ NCI_STATE state,
+ const char* name)
+{
+ TestState* test = g_object_new(TEST_TYPE_STATE, NULL);
+
+ nci_state_init_base(NCI_STATE(test), sm, state, name);
+ return test;
+}
+
+/*==========================================================================*
+ * Test transition
+ *==========================================================================*/
+
+typedef NciTransitionClass TestTransitionClass;
+typedef struct test_transition {
+ NciTransition transition;
+ gboolean fail_start;
+ int started;
+ int finished;
+} TestTransition;
+
+G_DEFINE_TYPE(TestTransition, test_transition, NCI_TYPE_TRANSITION)
+#define TEST_TYPE_TRANSITION (test_transition_get_type())
+#define TEST_TRANSITION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ TEST_TYPE_TRANSITION, TestTransition))
+
+static
+gboolean
+test_transition_start(
+ NciTransition* transition)
+{
+ TestTransition* self = TEST_TRANSITION(transition);
+
+ if (self->fail_start) {
+ return NCI_TRANSITION_CLASS(test_transition_parent_class)->
+ start(transition);
+ } else {
+ self->started++;
+ nci_transition_finish(transition, NULL);
+ return TRUE;
+ }
+}
+
+static
+void
+test_transition_finished(
+ NciTransition* transition)
+{
+ TestTransition* self = TEST_TRANSITION(transition);
+
+ self->finished++;
+ NCI_TRANSITION_CLASS(test_transition_parent_class)->finished(transition);
+}
+
+static
+void
+test_transition_init(
+ TestTransition* self)
+{
+}
+
+static
+void
+test_transition_class_init(
+ TestTransitionClass* klass)
+{
+ klass->start = test_transition_start;
+ klass->finished = test_transition_finished;
+}
+
+TestTransition*
+test_transition_new(
+ NciSm* sm,
+ NCI_STATE state)
+{
+ NciState* dest = nci_sm_get_state(sm, state);
+
+ if (dest) {
+ TestTransition* self = g_object_new(TEST_TYPE_TRANSITION, NULL);
+
+ nci_transition_init_base(&self->transition, sm, dest);
+ return self;
+ }
+ return NULL;
+}
+
+/*==========================================================================*
+ * null
+ *==========================================================================*/
+
+static
+void
+test_null(
+ void)
+{
+ NciSm* sm = nci_sm_new(NULL);
+ NciSm* null = NULL;
+ gulong zero = 0;
+
+ g_assert(!nci_param_w4_all_discoveries_new(NULL));
+
+ nci_sm_free(null);
+ nci_sm_handle_ntf(null, 0, 0, NULL);
+ nci_sm_add_state(null, NULL);
+ nci_sm_add_state(sm, NULL);
+ nci_sm_add_transition(null, NCI_STATE_INIT, NULL);
+ nci_sm_add_transition(sm, NCI_STATE_INIT, NULL);
+ g_assert(!nci_sm_add_last_state_handler(null, NULL, NULL));
+ g_assert(!nci_sm_add_last_state_handler(sm, NULL, NULL));
+ g_assert(!nci_sm_add_next_state_handler(null, NULL, NULL));
+ g_assert(!nci_sm_add_next_state_handler(sm, NULL, NULL));
+ g_assert(!nci_sm_add_intf_activated_handler(null, NULL, NULL));
+ g_assert(!nci_sm_add_intf_activated_handler(sm, NULL, NULL));
+ nci_sm_remove_handler(null, 0);
+ nci_sm_remove_handler(null, 1);
+ nci_sm_remove_handlers(null, NULL, 0);
+ nci_sm_remove_handlers(sm, &zero, 1);
+ g_assert(!nci_sm_sar(null));
+ g_assert(!nci_sm_sar(sm));
+ g_assert(!nci_sm_active_transition(null, NULL));
+ g_assert(!nci_sm_active_transition(sm, NULL));
+ nci_sm_add_weak_pointer(NULL);
+ nci_sm_add_weak_pointer(&null);
+ nci_sm_remove_weak_pointer(NULL);
+ nci_sm_remove_weak_pointer(&null);
+ g_assert(!nci_sm_get_state(null, NCI_STATE_INIT));
+ g_assert(!nci_sm_get_state(sm, INVALID_STATE));
+ g_assert(!nci_sm_enter_state(null, INVALID_STATE, NULL));
+ g_assert(!nci_sm_enter_state(sm, INVALID_STATE, NULL));
+ g_assert(!nci_sm_send_command(null, 0, 0, NULL, NULL, NULL));
+ g_assert(!nci_sm_send_command(sm, 0, 0, NULL, NULL, NULL));
+ g_assert(!nci_sm_send_command_static(null, 0, 0, NULL, 0, NULL, NULL));
+ g_assert(!nci_sm_send_command_static(sm, 0, 0, NULL, 0, NULL, NULL));
+ nci_sm_intf_activated(null, NULL);
+ nci_sm_stall(null, NCI_STALL_ERROR);
+ nci_sm_switch_to(null, NCI_STATE_INIT);
+ nci_sm_free(sm);
+}
+
+/*==========================================================================*
+ * state
+ *==========================================================================*/
+
+static
+void
+test_state(
+ void)
+{
+ NciSm* sm = nci_sm_new(NULL);
+ NciState* state = NCI_STATE(test_state_new(sm, TEST_STATE, "TEST"));
+ NciState* null = NULL;
+
+ g_assert(!nci_state_sm(null));
+ g_assert(!nci_state_ref(null));
+ nci_state_unref(null);
+ nci_state_add_transition(null, NULL);
+ nci_state_add_transition(state, NULL);
+ g_assert(!nci_state_get_transition(null, NCI_STATE_INIT));
+ g_assert(!nci_state_send_command(null, 0, 0, NULL, NULL, NULL));
+ nci_state_enter(null, NULL);
+ nci_state_reenter(null, NULL);
+ nci_state_leave(null);
+ nci_state_handle_ntf(null, 0, 0, NULL);
+
+ nci_state_unref(state);
+ nci_sm_free(sm);
+}
+
+/*==========================================================================*
+ * transition
+ *==========================================================================*/
+
+static
+void
+test_transition(
+ void)
+{
+ NciTransition* null = NULL;
+
+ g_assert(!nci_transition_sm(null));
+ g_assert(!nci_transition_ref(null));
+ nci_transition_unref(null);
+ nci_transition_stall(null, NCI_STALL_ERROR);
+ g_assert(!nci_transition_active(null));
+ g_assert(!nci_transition_start(null));
+ nci_transition_finish(null, NULL);
+ nci_transition_finished(null);
+ nci_transition_handle_ntf(null, 0, 0, NULL);
+ g_assert(!nci_transition_send_command(null, 0, 0, NULL, NULL));
+ g_assert(!nci_transition_send_command_static(null, 0, 0, NULL, 0, NULL));
+}
+
+/*==========================================================================*
+ * weak_ptr
+ *==========================================================================*/
+
+static
+void
+test_weak_ptr(
+ void)
+{
+ NciSm* sm = nci_sm_new(NULL);
+ NciSm* ptr1 = sm;
+ NciSm* ptr2 = sm;
+
+ nci_sm_add_weak_pointer(&ptr1);
+ nci_sm_add_weak_pointer(&ptr2);
+ nci_sm_remove_weak_pointer(&ptr1);
+ g_assert(!ptr1);
+ ptr1 = sm; /* It's no longer a weak pointer, it's just a pointer */
+
+ nci_sm_free(sm);
+ g_assert(ptr1);
+ g_assert(!ptr2);
+}
+
+/*==========================================================================*
+ * add_state
+ *==========================================================================*/
+
+static
+void
+test_add_state_cb(
+ NciSm* sm,
+ void* user_data)
+{
+ int* count = user_data;
+
+ g_assert(sm->last_state->state == TEST_STATE);
+ (*count)++;
+}
+
+static
+void
+test_add_state(
+ void)
+{
+ NciSm* sm = nci_sm_new(NULL);
+ TestState* test = test_state_new(sm, TEST_STATE, "TEST");
+ NciState* state = NCI_STATE(test);
+ int count = 0;
+ gulong id = nci_sm_add_last_state_handler(sm, test_add_state_cb, &count);
+
+ /* Second time doesn't do anything */
+ nci_sm_add_state(sm, state);
+ nci_sm_add_state(sm, state);
+
+ g_assert(nci_sm_get_state(sm, TEST_STATE) == state);
+ g_assert(nci_state_sm(state) == sm);
+ g_assert(!count);
+
+ /* Switch to our test state */
+ g_assert(nci_sm_enter_state(sm, TEST_STATE, NULL));
+ g_assert(test->entered == 1);
+ g_assert(!test->reentered);
+ g_assert(state->active);
+ g_assert(count == 1);
+
+ g_assert(nci_sm_enter_state(sm, TEST_STATE, NULL));
+ g_assert(test->entered == 1);
+ g_assert(test->reentered == 1);
+ g_assert(state->active);
+ g_assert(count == 1);
+
+ nci_sm_remove_handlers(sm, &id, 1);
+ g_assert(!id);
+
+ nci_sm_free(sm);
+ g_assert(!state->active);
+ g_assert(test->left == 1);
+
+ /* State is no longer associated with the state machine */
+ g_assert(!nci_state_sm(state));
+ nci_state_unref(state);
+}
+
+/*==========================================================================*
+ * last_state
+ *==========================================================================*/
+
+static
+void
+test_last_state_cb(
+ NciSm* sm,
+ void* user_data)
+{
+ g_assert(sm == user_data);
+ g_assert(sm->last_state->state == NCI_STATE_STOP);
+ nci_sm_free(sm);
+}
+
+static
+void
+test_last_state(
+ void)
+{
+ NciSm* sm = nci_sm_new(NULL);
+ gulong id = nci_sm_add_last_state_handler(sm, test_unreached_cb, sm);
+
+ /* Remove the dummy handler and add the real one */
+ g_assert(id);
+ nci_sm_remove_handler(sm, id);
+ g_assert(nci_sm_add_last_state_handler(sm, test_last_state_cb, sm));
+ nci_sm_add_weak_pointer(&sm);
+
+ /* Switching to the same state has no effect */
+ g_assert(sm->last_state->state == NCI_STATE_INIT);
+ g_assert(nci_sm_enter_state(sm, NCI_STATE_INIT, NULL));
+ g_assert(sm);
+
+ /* This will switch state to NCI_STATE_STOP, handler will delete NciSm
+ * and that will nullify the pointer */
+ nci_sm_stall(sm, NCI_STALL_STOP);
+ g_assert(!sm);
+}
+
+/*==========================================================================*
+ * next_state
+ *==========================================================================*/
+
+static
+void
+test_next_state_cb(
+ NciSm* sm,
+ void* user_data)
+{
+ g_assert(sm == user_data);
+ g_assert(sm->next_state->state == NCI_STATE_STOP);
+ nci_sm_free(sm);
+}
+
+static
+void
+test_next_state(
+ void)
+{
+ NciSm* sm = nci_sm_new(NULL);
+ gulong id = nci_sm_add_next_state_handler(sm, test_unreached_cb, sm);
+
+ /* Remove the dummy handler and add the real one */
+ g_assert(id);
+ nci_sm_remove_handler(sm, id);
+ g_assert(nci_sm_add_next_state_handler(sm, test_next_state_cb, sm));
+ nci_sm_add_weak_pointer(&sm);
+
+ /* Switching to the same state has no effect */
+ g_assert(sm->next_state->state == NCI_STATE_INIT);
+ g_assert(nci_sm_enter_state(sm, NCI_STATE_INIT, NULL));
+ g_assert(sm);
+
+ /* This will switch state to NCI_STATE_STOP, handler will delete NciSm
+ * and that will nullify the pointer */
+ nci_sm_stall(sm, NCI_STALL_STOP);
+ g_assert(!sm);
+}
+
+/*==========================================================================*
+ * transitions
+ *==========================================================================*/
+
+static
+void
+test_transitions(
+ void)
+{
+ NciSm* sm = nci_sm_new(NULL);
+ TestState* test_state = test_state_new(sm, TEST_STATE, "TEST");
+ TestTransition* test_transition;
+ int count = 0;
+ gulong id = nci_sm_add_next_state_handler(sm, test_count_cb, &count);
+
+ g_assert(nci_sm_get_state(sm, NCI_RFST_IDLE));
+ nci_sm_add_state(sm, NCI_STATE(test_state));
+ test_transition = test_transition_new(sm, TEST_STATE);
+ g_assert(test_transition);
+ nci_sm_add_transition(sm, NCI_RFST_IDLE, &test_transition->transition);
+
+ /* Simulate IDLE -> TEST switch failure */
+ test_transition->fail_start = TRUE;
+ g_assert(sm->last_state->state == NCI_STATE_INIT);
+ g_assert(nci_sm_enter_state(sm, NCI_RFST_IDLE, NULL));
+ g_assert(sm->last_state->state == NCI_RFST_IDLE);
+ g_assert(count == 1);
+ count = 0;
+
+ nci_sm_switch_to(sm, TEST_STATE);
+ g_assert(sm->last_state->state == NCI_STATE_ERROR);
+ g_assert(count == 1);
+ count = 0;
+
+ /* And then a success */
+ test_transition->fail_start = FALSE;
+ nci_sm_switch_to(sm, NCI_STATE_INIT);
+ g_assert(sm->last_state->state == NCI_STATE_INIT);
+ g_assert(count == 1);
+ count = 0;
+
+ g_assert(nci_sm_enter_state(sm, NCI_RFST_IDLE, NULL));
+ g_assert(sm->last_state->state == NCI_RFST_IDLE);
+ g_assert(count == 1);
+ count = 0;
+
+ g_assert(!test_transition->finished);
+ g_assert(!test_transition->started);
+ nci_sm_switch_to(sm, TEST_STATE);
+ g_assert(sm->last_state->state == TEST_STATE);
+ g_assert(test_transition->started == 1);
+ g_assert(test_transition->finished == 1);
+ g_assert(count == 1);
+ count = 0;
+
+ nci_sm_remove_handler(sm, id);
+ nci_sm_stall(sm, NCI_STALL_STOP);
+ nci_sm_free(sm);
+
+ nci_state_unref(NCI_STATE(test_state));
+ nci_transition_unref(NCI_TRANSITION(test_transition));
+}
+
+/*==========================================================================*
+ * Common
+ *==========================================================================*/
+
+#define TEST_(name) "/nci_sm/" name
+
+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_("state"), test_state);
+ g_test_add_func(TEST_("transition"), test_transition);
+ g_test_add_func(TEST_("weak_ptr"), test_weak_ptr);
+ g_test_add_func(TEST_("add_state"), test_add_state);
+ g_test_add_func(TEST_("last_state"), test_last_state);
+ g_test_add_func(TEST_("next_state"), test_next_state);
+ g_test_add_func(TEST_("transitions"), test_transitions);
+ test_init(&test_opt, argc, argv);
+ return g_test_run();
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/unit/nci_util/Makefile
^
|
@@ -0,0 +1,5 @@
+# -*- Mode: makefile-gmake -*-
+
+EXE = test_nci_util
+
+include ../common/Makefile
|
[-]
[+]
|
Added |
_service:tar_git:nfcd-binder-plugin-1.0.5.tar.bz2/unit/nci_util/test_nci_util.c
^
|
@@ -0,0 +1,423 @@
+/*
+ * Copyright (C) 2019 Jolla Ltd.
+ * Copyright (C) 2019 Slava Monich <slava.monich@jolla.com>
+ *
+ * You may use this file under the terms of BSD license as follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "test_common.h"
+
+#include "nci_util.h"
+
+static TestOpt test_opt;
+
+/*==========================================================================*
+ * null
+ *==========================================================================*/
+
+static
+void
+test_null(
+ void)
+{
+ g_assert(!nci_discovery_ntf_copy_array(NULL, 0));
+ g_assert(!nci_discovery_ntf_copy(NULL));
+}
+
+/*==========================================================================*
+ * mode_param_ok
+ *==========================================================================*/
+
+typedef struct test_mode_param_success_data {
+ const char* name;
+ NCI_MODE mode;
+ GUtilData data;
+ NciModeParam expected;
+} TestModeParamSuccessData;
+
+static
+void
+test_mode_param_success(
+ gconstpointer user_data)
+{
+ const TestModeParamSuccessData* test = user_data;
+ NciModeParam param;
+
+ memset(¶m, 0, sizeof(param));
+ g_assert(nci_parse_mode_param(¶m, test->mode,
+ test->data.bytes, test->data.size));
+ g_assert(!memcmp(¶m, &test->expected, sizeof(param)));
+}
+
+
+static const guint8 mode_param_success_data_minimal[] =
+ { 0x04, 0x00, 0x00, 0x00 };
+static const guint8 mode_param_success_data_full[] =
+ { 0x04, 0x00, 0x04, 0x37, 0xf4, 0x95, 0x95, 0x01, 0x20 };
+static const guint8 mode_param_success_data_no_nfcid1[] =
+ { 0x04, 0x00, 0x00, 0x01, 0x20 };
+static const guint8 mode_param_success_data_poll_b[] =
+ { 0x0b, 0x65, 0xe6, 0x70, 0x15, 0xe1, 0xf3, 0x5e, 0x11, 0x77, 0x87, 0x95 };
+static const guint8 mode_param_success_data_poll_b_rfu[] =
+ { 0x0b, 0x65, 0xe6, 0x70, 0x15, 0xe1, 0xf3, 0x5e, 0x11, 0x77, 0x97, 0x95 };
+static const TestModeParamSuccessData mode_param_success_tests[] = {
+ {
+ .name = "minimal",
+ .mode = NCI_MODE_ACTIVE_POLL_A,
+ .data = { TEST_ARRAY_AND_SIZE(mode_param_success_data_minimal) },
+ .expected = { .poll_a = { { 0x04, 0x00 } } }
+ },{
+ .name = "no_nfcid1",
+ .mode = NCI_MODE_ACTIVE_POLL_A,
+ .data = { TEST_ARRAY_AND_SIZE(mode_param_success_data_no_nfcid1) },
+ .expected = { .poll_a = { { 0x04, 0x00 }, 0, { 0 }, 1, 0x20 } }
+ },{
+ .name = "full",
+ .mode = NCI_MODE_PASSIVE_POLL_A,
+ .data = { TEST_ARRAY_AND_SIZE(mode_param_success_data_full) },
+ .expected = {
+ .poll_a = { {0x04, 0x00}, 4, {0x37, 0xf4, 0x95, 0x95}, 1, 0x20 }
+ }
+ },{
+ .name = "poll_b",
+ .mode = NCI_MODE_PASSIVE_POLL_B,
+ .data = { TEST_ARRAY_AND_SIZE(mode_param_success_data_poll_b) },
+ .expected = { .poll_b = { {0x65, 0xe6, 0x70, 0x15}, 256 } }
+ },{
+ .name = "poll_b_rfu", /* RFU part of FSCI to FSC conversion table */
+ .mode = NCI_MODE_PASSIVE_POLL_B,
+ .data = { TEST_ARRAY_AND_SIZE(mode_param_success_data_poll_b_rfu) },
+ .expected = { .poll_b = { {0x65, 0xe6, 0x70, 0x15}, 256 } }
+ }
+};
+
+/*==========================================================================*
+ * mode_param_fail
+ *==========================================================================*/
+
+typedef struct test_mode_param_fail_data {
+ const char* name;
+ NCI_MODE mode;
+ GUtilData data;
+} TestModeParamFailData;
+
+static
+void
+test_mode_param_fail(
+ gconstpointer user_data)
+{
+ const TestModeParamFailData* test = user_data;
+ NciModeParam param;
+
+ g_assert(!nci_parse_mode_param(¶m, test->mode,
+ test->data.bytes, test->data.size));
+}
+
+static const guint8 mode_param_fail_data_too_short_1[] =
+ { 0x00 };
+static const guint8 mode_param_fail_data_too_short_2[] =
+ { 0x04, 0x00, 0x04, 0x37, 0xf4 };
+static const guint8 mode_param_fail_data_too_short_3[] =
+ { 0x04, 0x00, 0x04, 0x37, 0xf4, 0x95, 0x95, 0x01 };
+static const guint8 mode_param_fail_data_too_long[] =
+ { 0x04, 0x00, 0x0b /* exceeds max 10 */, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x20 };
+static const guint8 mode_param_fail_pollb_data_too_short_1[] =
+ { 0x0a, 0x65, 0xe6, 0x70, 0x15, 0xe1, 0xf3, 0x5e, 0x11, 0x77, 0x87 };
+static const TestModeParamFailData mode_param_fail_tests[] = {
+ {
+ .name = "unhandled_mode",
+ .mode = NCI_MODE_PASSIVE_LISTEN_15693
+ },{
+ .name = "passive_poll_a_empty",
+ .mode = NCI_MODE_PASSIVE_POLL_A,
+ .data = { NULL, 0 }
+ },{
+ .name = "active_poll_a_empty",
+ .mode = NCI_MODE_ACTIVE_POLL_A,
+ .data = { NULL, 0 }
+ },{
+ .name = "too_short/poll_a",
+ .mode = NCI_MODE_ACTIVE_POLL_A,
+ .data = { TEST_ARRAY_AND_SIZE(mode_param_fail_data_too_short_1) }
+ },{
+ .name = "too_short/poll_b",
+ .mode = NCI_MODE_ACTIVE_POLL_A,
+ .data = { TEST_ARRAY_AND_SIZE(mode_param_fail_data_too_short_1) }
+ },{
+ .name = "too_short/2",
+ .mode = NCI_MODE_ACTIVE_POLL_A,
+ .data = { TEST_ARRAY_AND_SIZE(mode_param_fail_data_too_short_2) }
+ },{
+ .name = "too_short/3",
+ .mode = NCI_MODE_ACTIVE_POLL_A,
+ .data = { TEST_ARRAY_AND_SIZE(mode_param_fail_data_too_short_3) }
+ },{
+ .name = "too_long",
+ .mode = NCI_MODE_ACTIVE_POLL_A,
+ .data = { TEST_ARRAY_AND_SIZE(mode_param_fail_data_too_long) }
+ },{
+ .name = "poll_b_empty",
+ .mode = NCI_MODE_PASSIVE_POLL_B,
+ .data = { NULL, 0 }
+ },{
+ .name = "poll_b_too_short",
+ .mode = NCI_MODE_PASSIVE_POLL_B,
+ .data = { TEST_ARRAY_AND_SIZE(mode_param_fail_pollb_data_too_short_1) }
+ }
+};
+
+/*==========================================================================*
+ * discover_success
+ *==========================================================================*/
+
+typedef struct test_discover_success_data {
+ const char* name;
+ GUtilData data;
+ NciDiscoveryNtf ntf;
+} TestDiscoverSuccessData;
+
+static
+void
+test_discover_success(
+ gconstpointer test_data)
+{
+ const TestDiscoverSuccessData* test = test_data;
+ const GUtilData* pkt = &test->data;
+ NciDiscoveryNtf ntf;
+ NciModeParam param;
+
+ g_assert(nci_parse_discover_ntf(&ntf, NULL, pkt->bytes, pkt->size));
+ g_assert(nci_parse_discover_ntf(&ntf, ¶m, pkt->bytes, pkt->size));
+}
+
+static const guint8 discover_success_data_no_param[] =
+ { 0x01, 0x04, 0x00, 0x00, 0x02 };
+static const NciModeParam discover_success_data_full_1_param = {
+ .poll_a = { {0x04, 0x00}, 4, { 0x4f, 0x01, 0x74, 0x01 }, 1, 0x20 }
+};
+static const guint8 discover_success_data_full_1[] =
+ { 0x01, 0x04, 0x00, 0x09, 0x04, 0x00, 0x04, 0x4f,
+ 0x01, 0x74, 0x01, 0x01, 0x20, 0x02 };
+static const NciModeParam discover_success_data_full_2_param = {
+ .poll_a = { {0x04, 0x00}, 4, { 0x4f, 0x01, 0x74, 0x01 }, 1, 0x08 }
+};
+static const guint8 discover_success_data_full_2[] =
+ { 0x02, 0x80, 0x00, 0x09, 0x04, 0x00, 0x04, 0x4f,
+ 0x01, 0x74, 0x01, 0x01, 0x08, 0x00 };
+
+static const TestDiscoverSuccessData discover_success_tests[] = {
+ {
+ .name = "no_param",
+ .data = { TEST_ARRAY_AND_SIZE(discover_success_data_no_param) },
+ .ntf = { .discovery_id = 0x01, .protocol = NCI_PROTOCOL_ISO_DEP,
+ .mode = NCI_MODE_PASSIVE_POLL_A, .param_len = 0,
+ .last = FALSE }
+ },{
+ .name = "full/1",
+ .data = { TEST_ARRAY_AND_SIZE(discover_success_data_full_1) },
+ .ntf = { .discovery_id = 0x01, .protocol = NCI_PROTOCOL_ISO_DEP,
+ .mode = NCI_MODE_PASSIVE_POLL_A, .param_len = 9,
+ .param_bytes = discover_success_data_full_1 + 4,
+ .param = &discover_success_data_full_1_param,
+ .last = FALSE }
+ },{
+ .name = "full/2",
+ .data = { TEST_ARRAY_AND_SIZE(discover_success_data_full_2) },
+ .ntf = { .discovery_id = 0x01, .protocol = 0x80,
+ .mode = NCI_MODE_PASSIVE_POLL_A, .param_len = 9,
+ .param_bytes = discover_success_data_full_2 + 4,
+ .param = &discover_success_data_full_2_param,
+ .last = TRUE }
+ }
+};
+
+/*==========================================================================*
+ * discover_copy
+ *==========================================================================*/
+
+static
+void
+test_discover_copy_check(
+ const NciDiscoveryNtf* n1,
+ const NciDiscoveryNtf* n2)
+{
+ g_assert(n1);
+ g_assert(n1->discovery_id == n2->discovery_id);
+ g_assert(n1->protocol == n2->protocol);
+ g_assert(n1->mode == n2->mode);
+ g_assert(n1->param_len == n2->param_len);
+ g_assert(n1->last == n2->last);
+
+ if (n2->param_bytes) {
+ g_assert(n1->param_bytes);
+ g_assert(!memcmp(n1->param_bytes, n2->param_bytes, n2->param_len));
+ } else {
+ g_assert(!n1->param_bytes);
+ }
+
+ if (n2->param) {
+ g_assert(n1->param);
+ g_assert(!memcmp(n1->param_bytes, n2->param_bytes, n2->param_len));
+ switch (n2->mode) {
+ case NCI_MODE_ACTIVE_POLL_A:
+ case NCI_MODE_PASSIVE_POLL_A:
+ {
+ const NciModeParamPollA* p1 = &n1->param->poll_a;
+ const NciModeParamPollA* p2 = &n2->param->poll_a;
+
+ g_assert(p1->sens_res[0] == p2->sens_res[0]);
+ g_assert(p1->sens_res[1] == p2->sens_res[1]);
+ g_assert(p1->nfcid1_len == p2->nfcid1_len);
+ g_assert(p1->sel_res_len == p2->sel_res_len);
+ g_assert(p1->sel_res == p2->sel_res);
+ g_assert(!memcmp(p1->nfcid1, p2->nfcid1, p2->nfcid1_len));
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ g_assert(!n1->param);
+ }
+}
+
+static
+void
+test_discover_copy(
+ gconstpointer test_data)
+{
+ const TestDiscoverSuccessData* test = test_data;
+ NciDiscoveryNtf ntf = test->ntf;
+ NciDiscoveryNtf* copy = nci_discovery_ntf_copy(&test->ntf);
+
+ test_discover_copy_check(&test->ntf, copy);
+ g_free(copy);
+
+ ntf.param = NULL;
+ copy = nci_discovery_ntf_copy(&ntf);
+ test_discover_copy_check(&ntf, copy);
+ g_free(copy);
+}
+
+/*==========================================================================*
+ * discover_fail
+ *==========================================================================*/
+
+typedef struct test_discover_fail_data {
+ const char* name;
+ GUtilData data;
+} TestDiscoverFailData;
+
+static
+void
+test_discover_fail(
+ gconstpointer test_data)
+{
+ const TestDiscoverFailData* test = test_data;
+ const GUtilData* pkt = &test->data;
+ NciDiscoveryNtf ntf;
+ NciModeParam param;
+
+ g_assert(!nci_parse_discover_ntf(&ntf, ¶m, pkt->bytes, pkt->size));
+}
+
+static const guint8 discover_fail_data_too_short_1[] =
+ { 0x01, 0x04, 0x00, 0x09 };
+static const guint8 discover_fail_data_too_short_2[] =
+ { 0x01, 0x04, 0x00, 0x09, 0x04, 0x00, 0x04, 0x4f };
+static const guint8 discover_fail_data_too_short_3[] =
+ { 0x01, 0x04, 0x00, 0x09, 0x04, 0x00, 0x04, 0x4f,
+ 0x01, 0x74, 0x01, 0x01, 0x20 };
+static const TestDiscoverFailData discover_fail_tests[] = {
+ {
+ .name = "too_short/1",
+ .data = { TEST_ARRAY_AND_SIZE(discover_fail_data_too_short_1) }
+ },{
+ .name = "too_short/2",
+ .data = { TEST_ARRAY_AND_SIZE(discover_fail_data_too_short_2) }
+ },{
+ .name = "too_short/3",
+ .data = { TEST_ARRAY_AND_SIZE(discover_fail_data_too_short_2) }
+ }
+};
+
+/*==========================================================================*
+ * Common
+ *==========================================================================*/
+
+#define TEST_(name) "/nci_util/" name
+
+int main(int argc, char* argv[])
+{
+ guint i;
+
+ g_test_init(&argc, &argv, NULL);
+ test_init(&test_opt, argc, argv);
+ g_test_add_func(TEST_("null"), test_null);
+ for (i = 0; i < G_N_ELEMENTS(mode_param_success_tests); i++) {
+ const TestModeParamSuccessData* test = mode_param_success_tests + i;
+ char* path = g_strconcat(TEST_("mode_param/ok/"), test->name, NULL);
+
+ g_test_add_data_func(path, test, test_mode_param_success);
+ g_free(path);
+ }
+ for (i = 0; i < G_N_ELEMENTS(mode_param_fail_tests); i++) {
+ const TestModeParamFailData* test = mode_param_fail_tests + i;
+ char* path = g_strconcat(TEST_("mode_param/fail/"), test->name, NULL);
+
+ g_test_add_data_func(path, test, test_mode_param_fail);
+ g_free(path);
+ }
+ for (i = 0; i < G_N_ELEMENTS(discover_success_tests); i++) {
+ const TestDiscoverSuccessData* test = discover_success_tests + i;
+ char* path1 = g_strconcat(TEST_("discover/success/"), test->name, NULL);
+ char* path2 = g_strconcat(TEST_("discover/copy/"), test->name, NULL);
+
+ g_test_add_data_func(path1, test, test_discover_success);
+ g_test_add_data_func(path2, test, test_discover_copy);
+ g_free(path1);
+ g_free(path2);
+ }
+ for (i = 0; i < G_N_ELEMENTS(discover_fail_tests); i++) {
+ const TestDiscoverFailData* test = discover_fail_tests + i;
+ char* path = g_strconcat(TEST_("discover/fail/"), test->name, NULL);
+
+ g_test_add_data_func(path, test, test_discover_fail);
+ g_free(path);
+ }
+ return g_test_run();
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
|