Created
May 15, 2018 03:56
-
-
Save isundaylee/f9ff1dc259619eec0d1b62c2c5abf4fc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* Copyright (c) 2010 - 2018, Nordic Semiconductor ASA | |
| * All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without modification, | |
| * are permitted provided that the following conditions are met: | |
| * | |
| * 1. Redistributions of source code must retain the above copyright notice, this | |
| * list of conditions and the following disclaimer. | |
| * | |
| * 2. Redistributions in binary form, except as embedded into a Nordic | |
| * Semiconductor ASA integrated circuit in a product or a software update for | |
| * such product, must reproduce the above copyright notice, this list of | |
| * conditions and the following disclaimer in the documentation and/or other | |
| * materials provided with the distribution. | |
| * | |
| * 3. Neither the name of Nordic Semiconductor ASA nor the names of its | |
| * contributors may be used to endorse or promote products derived from this | |
| * software without specific prior written permission. | |
| * | |
| * 4. This software, with or without modification, must only be used with a | |
| * Nordic Semiconductor ASA integrated circuit. | |
| * | |
| * 5. Any software provided in binary form under this license must not be reverse | |
| * engineered, decompiled, modified and/or disassembled. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS | |
| * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
| * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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 "simple_on_off_client.h" | |
| #include "simple_on_off_common.h" | |
| #include <stdint.h> | |
| #include <stddef.h> | |
| #include "access.h" | |
| #include "access_config.h" | |
| #include "access_reliable.h" | |
| #include "device_state_manager.h" | |
| #include "nrf_mesh.h" | |
| #include "nrf_mesh_assert.h" | |
| #include "log.h" | |
| /***************************************************************************** | |
| * Static variables | |
| *****************************************************************************/ | |
| /** Keeps a single global TID for all transfers. */ | |
| static uint8_t m_tid; | |
| /***************************************************************************** | |
| * Static functions | |
| *****************************************************************************/ | |
| static void reliable_status_cb(access_model_handle_t model_handle, | |
| void * p_args, | |
| access_reliable_status_t status) | |
| { | |
| simple_on_off_client_t * p_client = p_args; | |
| NRF_MESH_ASSERT(p_client->status_cb != NULL); | |
| p_client->state.reliable_transfer_active = false; | |
| switch (status) | |
| { | |
| case ACCESS_RELIABLE_TRANSFER_SUCCESS: | |
| /* Ignore */ | |
| break; | |
| case ACCESS_RELIABLE_TRANSFER_TIMEOUT: | |
| p_client->status_cb(p_client, SIMPLE_ON_OFF_STATUS_ERROR_NO_REPLY, NRF_MESH_ADDR_UNASSIGNED); | |
| break; | |
| case ACCESS_RELIABLE_TRANSFER_CANCELLED: | |
| p_client->status_cb(p_client, SIMPLE_ON_OFF_STATUS_CANCELLED, NRF_MESH_ADDR_UNASSIGNED); | |
| break; | |
| default: | |
| /* Should not be possible. */ | |
| NRF_MESH_ASSERT(false); | |
| break; | |
| } | |
| } | |
| /** Returns @c true if the message received was from the address corresponding to the clients | |
| * publish address. */ | |
| static bool is_valid_source(const simple_on_off_client_t * p_client, | |
| const access_message_rx_t * p_message) | |
| { | |
| /* Check the originator of the status. */ | |
| dsm_handle_t publish_handle; | |
| nrf_mesh_address_t publish_address; | |
| if (access_model_publish_address_get(p_client->model_handle, &publish_handle) != NRF_SUCCESS || | |
| publish_handle == DSM_HANDLE_INVALID || | |
| dsm_address_get(publish_handle, &publish_address) != NRF_SUCCESS || | |
| publish_address.value != p_message->meta_data.src.value) | |
| { | |
| return false; | |
| } | |
| else | |
| { | |
| return true; | |
| } | |
| } | |
| static uint32_t send_reliable_message(const simple_on_off_client_t * p_client, | |
| simple_on_off_opcode_t opcode, | |
| const uint8_t * p_data, | |
| uint16_t length) | |
| { | |
| access_reliable_t reliable; | |
| reliable.model_handle = p_client->model_handle; | |
| reliable.message.p_buffer = p_data; | |
| reliable.message.length = length; | |
| reliable.message.opcode.opcode = opcode; | |
| reliable.message.opcode.company_id = SIMPLE_ON_OFF_COMPANY_ID; | |
| reliable.message.force_segmented = false; | |
| reliable.message.transmic_size = NRF_MESH_TRANSMIC_SIZE_DEFAULT; | |
| reliable.reply_opcode.opcode = SIMPLE_ON_OFF_OPCODE_STATUS; | |
| reliable.reply_opcode.company_id = SIMPLE_ON_OFF_COMPANY_ID; | |
| reliable.timeout = ACCESS_RELIABLE_TIMEOUT_MIN; | |
| reliable.status_cb = reliable_status_cb; | |
| return access_model_reliable_publish(&reliable); | |
| } | |
| /***************************************************************************** | |
| * Opcode handler callback(s) | |
| *****************************************************************************/ | |
| static void handle_status_cb(access_model_handle_t handle, const access_message_rx_t * p_message, void * p_args) | |
| { | |
| simple_on_off_client_t * p_client = p_args; | |
| NRF_MESH_ASSERT(p_client->status_cb != NULL); | |
| if (!is_valid_source(p_client, p_message)) | |
| { | |
| return; | |
| } | |
| simple_on_off_msg_status_t * p_status = | |
| (simple_on_off_msg_status_t *) p_message->p_data; | |
| simple_on_off_status_t on_off_status = (p_status->present_on_off ? | |
| SIMPLE_ON_OFF_STATUS_ON : SIMPLE_ON_OFF_STATUS_OFF); | |
| p_client->status_cb(p_client, on_off_status, p_message->meta_data.src.value); | |
| } | |
| static const access_opcode_handler_t m_opcode_handlers[] = | |
| { | |
| {{SIMPLE_ON_OFF_OPCODE_STATUS, SIMPLE_ON_OFF_COMPANY_ID}, handle_status_cb} | |
| }; | |
| static void handle_publish_timeout(access_model_handle_t handle, void * p_args) | |
| { | |
| simple_on_off_client_t * p_client = p_args; | |
| if (p_client->timeout_cb != NULL) | |
| { | |
| p_client->timeout_cb(handle, p_args); | |
| } | |
| } | |
| /***************************************************************************** | |
| * Public API | |
| *****************************************************************************/ | |
| uint32_t simple_on_off_client_init(simple_on_off_client_t * p_client, uint16_t element_index) | |
| { | |
| if (p_client == NULL || | |
| p_client->status_cb == NULL) | |
| { | |
| return NRF_ERROR_NULL; | |
| } | |
| access_model_add_params_t init_params; | |
| init_params.model_id.model_id = SIMPLE_ON_OFF_CLIENT_MODEL_ID; | |
| init_params.model_id.company_id = SIMPLE_ON_OFF_COMPANY_ID; | |
| init_params.element_index = element_index; | |
| init_params.p_opcode_handlers = &m_opcode_handlers[0]; | |
| init_params.opcode_count = sizeof(m_opcode_handlers) / sizeof(m_opcode_handlers[0]); | |
| init_params.p_args = p_client; | |
| init_params.publish_timeout_cb = handle_publish_timeout; | |
| return access_model_add(&init_params, &p_client->model_handle); | |
| } | |
| uint32_t simple_on_off_client_set(simple_on_off_client_t * p_client, bool on_off) | |
| { | |
| if (p_client == NULL || p_client->status_cb == NULL) | |
| { | |
| return NRF_ERROR_NULL; | |
| } | |
| else if (p_client->state.reliable_transfer_active) | |
| { | |
| return NRF_ERROR_INVALID_STATE; | |
| } | |
| p_client->state.data.on_off = on_off ? 1 : 0; | |
| p_client->state.data.tid = m_tid++; | |
| uint32_t status = send_reliable_message(p_client, | |
| SIMPLE_ON_OFF_OPCODE_SET, | |
| (const uint8_t *)&p_client->state.data, | |
| sizeof(simple_on_off_msg_set_t)); | |
| if (status == NRF_SUCCESS) | |
| { | |
| p_client->state.reliable_transfer_active = true; | |
| } | |
| return status; | |
| } | |
| uint32_t simple_on_off_client_set_unreliable(simple_on_off_client_t * p_client, bool on_off, uint8_t repeats) | |
| { | |
| simple_on_off_msg_set_unreliable_t set_unreliable; | |
| set_unreliable.on_off = on_off ? 1 : 0; | |
| set_unreliable.tid = m_tid++; | |
| access_message_tx_t message; | |
| message.opcode.opcode = SIMPLE_ON_OFF_OPCODE_SET_UNRELIABLE; | |
| message.opcode.company_id = SIMPLE_ON_OFF_COMPANY_ID; | |
| message.p_buffer = (const uint8_t*) &set_unreliable; | |
| message.length = sizeof(set_unreliable); | |
| message.force_segmented = false; | |
| message.transmic_size = NRF_MESH_TRANSMIC_SIZE_DEFAULT; | |
| uint32_t status = NRF_SUCCESS; | |
| for (uint8_t i = 0; i < repeats; ++i) | |
| { | |
| status = access_model_publish(p_client->model_handle, &message); | |
| if (status != NRF_SUCCESS) | |
| { | |
| break; | |
| } | |
| } | |
| return status; | |
| } | |
| uint32_t simple_on_off_client_get(simple_on_off_client_t * p_client) | |
| { | |
| if (p_client == NULL || p_client->status_cb == NULL) | |
| { | |
| return NRF_ERROR_NULL; | |
| } | |
| else if (p_client->state.reliable_transfer_active) | |
| { | |
| return NRF_ERROR_INVALID_STATE; | |
| } | |
| uint32_t status = send_reliable_message(p_client, | |
| SIMPLE_ON_OFF_OPCODE_GET, | |
| NULL, | |
| 0); | |
| if (status == NRF_SUCCESS) | |
| { | |
| p_client->state.reliable_transfer_active = true; | |
| } | |
| return status; | |
| } | |
| /** | |
| * Cancel any ongoing reliable message transfer. | |
| * | |
| * @param[in] p_client Pointer to the client instance structure. | |
| */ | |
| void simple_on_off_client_pending_msg_cancel(simple_on_off_client_t * p_client) | |
| { | |
| (void)access_model_reliable_cancel(p_client->model_handle); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment