Hi,
I have a mesh network with multiple smartphones, which are connected over GATT. If now a light command is triggered on one smartphone, I want to synchronize the other smarthpones, but I am currently unsure where to tackled this problem. I think I can check all GATT connections on every node and then notify each smartphone connected, right? But how can I allocate a specific message for a GATT connection? I see, that in the light switch examples, only the access_model_reply() in access.c is used, but never a notification is sent from a node to the smarthpone?
So, how can I publish a specific message with specific opcode to a GATT connected smartphone?
Edit:
So I did the following and used the GATT connection:
void send_data_to_smartphone(uint8_t *data, uint16_t size) { for(uint8_t i = 0; i < MESH_GATT_CONNECTION_COUNT_MAX; i++) { if(BLE_CONN_HANDLE_INVALID != m_gatt.connections[i].conn_handle) { uint8_t * p_packet = mesh_gatt_packet_alloc(i, MESH_GATT_PDU_TYPE_NETWORK_PDU,size, 0); /* We should not have any other GATT stuff going on at this point. */ NRF_MESH_ASSERT(p_packet != NULL); memcpy(p_packet, data, size); NRF_MESH_ERROR_CHECK(mesh_gatt_packet_send(i, p_packet)); __LOG(LOG_SRC_BEARER, LOG_LEVEL_INFO, "Send Packet with length %d to Handle %d\n", size, i); } } }
And I receive the message on the Smartphone correctly in
protected void parseMeshPduNotifications(@NonNull final byte[] pdu, @NonNull final MeshNetwork network) throws ExtendedInvalidCipherTextException { final List<NetworkKey> networkKeys = network.getNetKeys(); final int ivi = ((pdu[1] & 0xFF) >>> 7) & 0x01; final int nid = pdu[1] & 0x7F; //Here we go through all the network keys and filter out network keys based on the nid. for (int i = 0; i < networkKeys.size(); i++) { NetworkKey networkKey = networkKeys.get(i); final SecureUtils.K2Output k2Output = SecureUtils.calculateK2(networkKey.getKey(), SecureUtils.K2_MASTER_INPUT); if (nid == k2Output.getNid()) { final byte[] networkHeader = deObfuscateNetworkHeader(pdu, MeshParserUtils.intToBytes(network.getIvIndex()), k2Output.getPrivacyKey()); if (networkHeader != null) { final int ctlTtl = networkHeader[0]; final int ctl = (ctlTtl >> 7) & 0x01; final int ttl = ctlTtl & 0x7F; Log.v(TAG, "TTL for received message: " + ttl); final byte[] sequenceNumber = ByteBuffer.allocate(3).order(ByteOrder.BIG_ENDIAN).put(networkHeader, 1, 3).array(); final int src = MeshParserUtils.unsignedBytesToInt(networkHeader[5], networkHeader[4]); final int sequenceNo = MeshParserUtils.getSequenceNumber(sequenceNumber); Log.v(TAG, "Sequence number of received access message: " + MeshParserUtils.getSequenceNumber(sequenceNumber)); final ProvisionedMeshNode node = network.getNode(src); if (node != null) { //Check if the sequence number has been incremented since the last message sent and return null if not if (sequenceNo > node.getSequenceNumber()) { if (!MeshParserUtils.isValidSequenceNumber(sequenceNo)) { return; } node.setSequenceNumber(sequenceNo); } else { return; } } else { return; } //TODO validate ivi byte[] nonce; final byte[] ivIndex = MeshParserUtils.intToBytes(network.getIvIndex()); try { final int networkPayloadLength = pdu.length - (2 + networkHeader.length); final byte[] transportPdu = new byte[networkPayloadLength]; System.arraycopy(pdu, 8, transportPdu, 0, networkPayloadLength); final byte[] decryptedNetworkPayload; final MeshMessageState state; if (pdu[0] == MeshManagerApi.PDU_TYPE_NETWORK) { nonce = createNetworkNonce((byte) ctlTtl, sequenceNumber, src, ivIndex); decryptedNetworkPayload = SecureUtils.decryptCCM(transportPdu, k2Output.getEncryptionKey(), nonce, SecureUtils.getNetMicLength(ctl)); state = getState(src); } else { nonce = createProxyNonce(sequenceNumber, src, ivIndex); decryptedNetworkPayload = SecureUtils.decryptCCM(transportPdu, k2Output.getEncryptionKey(), nonce, SecureUtils.getNetMicLength(ctl)); state = getState(MeshAddress.UNASSIGNED_ADDRESS); } if (state != null) { //TODO look in to proxy filter messages ((DefaultNoOperationMessageState) state).parseMeshPdu(node, pdu, networkHeader, decryptedNetworkPayload); return; } } catch (InvalidCipherTextException ex) { if (i == networkKeys.size() - 1) { throw new ExtendedInvalidCipherTextException(ex.getMessage(), ex.getCause(), TAG); } } } } } }
But there seems to be a problem with the network key for this packet. Do I need to code my message before sending it over GATT?
Edit 2: The problem seems to be with the network ID and the network header. How do I need to add this on my nRF52833? Are there already some functionalities that provide these?