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?