26
26
27
27
#include " nRF5xn.h"
28
28
29
+ namespace {
30
+
31
+ static const ble_gatts_rw_authorize_reply_params_t write_auth_queue_full_reply = {
32
+ .type = BLE_GATTS_AUTHORIZE_TYPE_WRITE,
33
+ .params = {
34
+ .write = {
35
+ .gatt_status = BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL
36
+ }
37
+ }
38
+ };
39
+
40
+ static const ble_gatts_rw_authorize_reply_params_t write_auth_invalid_offset_reply = {
41
+ .type = BLE_GATTS_AUTHORIZE_TYPE_WRITE,
42
+ .params = {
43
+ .write = {
44
+ .gatt_status = BLE_GATT_STATUS_ATTERR_INVALID_OFFSET
45
+ }
46
+ }
47
+ };
48
+
49
+ static const ble_gatts_rw_authorize_reply_params_t write_auth_succes_reply = {
50
+ .type = BLE_GATTS_AUTHORIZE_TYPE_WRITE,
51
+ .params = {
52
+ .write = {
53
+ .gatt_status = BLE_GATT_STATUS_SUCCESS,
54
+ .update = 0
55
+ }
56
+ }
57
+ };
58
+
59
+ static const ble_gatts_rw_authorize_reply_params_t write_auth_invalid_reply = {
60
+ .type = BLE_GATTS_AUTHORIZE_TYPE_WRITE,
61
+ .params = {
62
+ .write = {
63
+ .gatt_status = BLE_GATT_STATUS_ATTERR_INVALID
64
+ }
65
+ }
66
+ };
67
+
68
+ }
69
+
29
70
/* *************************************************************************/
30
71
/* !
31
72
@brief Adds a new service to the GATT table on the peripheral
@@ -354,6 +395,8 @@ ble_error_t nRF5xGattServer::reset(void)
354
395
memset (nrfDescriptorHandles, 0 , sizeof (nrfDescriptorHandles));
355
396
descriptorCount = 0 ;
356
397
398
+ releaseAllWriteRequests ();
399
+
357
400
return BLE_ERROR_NONE;
358
401
}
359
402
@@ -427,13 +470,33 @@ void nRF5xGattServer::hwCallback(ble_evt_t *p_ble_evt)
427
470
}
428
471
break ;
429
472
473
+ case BLE_EVT_USER_MEM_REQUEST: {
474
+ uint16_t conn_handle = p_ble_evt->evt .common_evt .conn_handle ;
475
+
476
+ // allocate a new long request for this connection
477
+ // NOTE: we don't care about the result at this stage,
478
+ // it is not possible to cancel the operation anyway.
479
+ // If the request was not allocated then it will gracefully failled
480
+ // at subsequent stages.
481
+ allocateLongWriteRequest (conn_handle);
482
+ sd_ble_user_mem_reply (conn_handle, NULL );
483
+ return ;
484
+ }
485
+
430
486
default :
431
487
return ;
432
488
}
433
489
434
490
int characteristicIndex = resolveValueHandleToCharIndex (handle_value);
435
491
if (characteristicIndex == -1 ) {
436
- return ;
492
+ // filter out the case were the request is a long one,
493
+ // and there is no attribute handle provided
494
+ uint8_t write_op = gattsEventP->params .authorize_request .request .write .op ;
495
+ if (eventType != GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ ||
496
+ (write_op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW &&
497
+ write_op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)) {
498
+ return ;
499
+ }
437
500
}
438
501
439
502
/* Find index (charHandle) in the pool */
@@ -451,6 +514,131 @@ void nRF5xGattServer::hwCallback(ble_evt_t *p_ble_evt)
451
514
break ;
452
515
}
453
516
case GattServerEvents::GATT_EVENT_WRITE_AUTHORIZATION_REQ: {
517
+ uint16_t conn_handle = gattsEventP->conn_handle ;
518
+ const ble_gatts_evt_write_t & input_req = gattsEventP->params .authorize_request .request .write ;
519
+ const uint16_t max_size = getBiggestCharacteristicSize ();
520
+
521
+ // this is a long write request, handle it here.
522
+ switch (input_req.op ) {
523
+ case BLE_GATTS_OP_PREP_WRITE_REQ: {
524
+ // verify that the request is not outside of the possible range
525
+ if ((input_req.offset + input_req.len ) > max_size) {
526
+ sd_ble_gatts_rw_authorize_reply (conn_handle, &write_auth_invalid_offset_reply);
527
+ releaseLongWriteRequest (conn_handle);
528
+ return ;
529
+ }
530
+
531
+ // find the write request
532
+ long_write_request_t * req = findLongWriteRequest (conn_handle);
533
+ if (!req) {
534
+ sd_ble_gatts_rw_authorize_reply (conn_handle, &write_auth_invalid_reply);
535
+ return ;
536
+ }
537
+
538
+ // initialize the first request by setting the offset
539
+ if (req->length == 0 ) {
540
+ req->attr_handle = input_req.handle ;
541
+ req->offset = input_req.offset ;
542
+ } else {
543
+ // it should be the subsequent write
544
+ if ((req->offset + req->length ) != input_req.offset ) {
545
+ sd_ble_gatts_rw_authorize_reply (conn_handle, &write_auth_invalid_offset_reply);
546
+ releaseLongWriteRequest (conn_handle);
547
+ return ;
548
+ }
549
+
550
+ // it is not allowed to write multiple characteristic with the same request
551
+ if (input_req.handle != req->attr_handle ) {
552
+ sd_ble_gatts_rw_authorize_reply (conn_handle, &write_auth_invalid_reply);
553
+ releaseLongWriteRequest (conn_handle);
554
+ return ;
555
+ }
556
+ }
557
+
558
+ // start the copy of what is in input
559
+ memcpy (req->data + req->length , input_req.data , input_req.len );
560
+
561
+ // update the lenght of the data written
562
+ req->length = req->length + input_req.len ;
563
+
564
+ // success, signal it to the softdevice
565
+ ble_gatts_rw_authorize_reply_params_t reply = {
566
+ .type = BLE_GATTS_AUTHORIZE_TYPE_WRITE,
567
+ .params = {
568
+ .write = {
569
+ .gatt_status = BLE_GATT_STATUS_SUCCESS,
570
+ .update = 1 ,
571
+ .offset = input_req.offset ,
572
+ .len = input_req.len ,
573
+ .p_data = input_req.data
574
+ }
575
+ }
576
+ };
577
+
578
+ sd_ble_gatts_rw_authorize_reply (conn_handle, &reply);
579
+ } return ;
580
+
581
+ case BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL: {
582
+ releaseLongWriteRequest (conn_handle);
583
+ sd_ble_gatts_rw_authorize_reply (conn_handle, &write_auth_succes_reply);
584
+ } return ;
585
+
586
+ case BLE_GATTS_OP_EXEC_WRITE_REQ_NOW: {
587
+ long_write_request_t * req = findLongWriteRequest (conn_handle);
588
+ if (!req) {
589
+ sd_ble_gatts_rw_authorize_reply (conn_handle, &write_auth_invalid_reply);
590
+ return ;
591
+ }
592
+
593
+ GattWriteAuthCallbackParams cbParams = {
594
+ .connHandle = conn_handle,
595
+ .handle = req->attr_handle ,
596
+ .offset = req->offset ,
597
+ .len = req->length ,
598
+ .data = req->data ,
599
+ .authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
600
+ * set to AUTH_CALLBACK_REPLY_SUCCESS if the client
601
+ * request is to proceed. */
602
+ };
603
+ uint16_t write_authorization = p_characteristics[characteristicIndex]->authorizeWrite (&cbParams);
604
+
605
+ // the user code didn't provide the write authorization,
606
+ // just leave here.
607
+ if (write_authorization != AUTH_CALLBACK_REPLY_SUCCESS) {
608
+ // report the status of the operation in any cases
609
+ sd_ble_gatts_rw_authorize_reply (conn_handle, &write_auth_invalid_reply);
610
+ releaseLongWriteRequest (conn_handle);
611
+ return ;
612
+ }
613
+
614
+ // FIXME can't use ::write here, this function doesn't take the offset into account ...
615
+ ble_gatts_value_t value = {
616
+ .len = req->length ,
617
+ .offset = req->offset ,
618
+ .p_value = req->data
619
+ };
620
+ uint32_t update_err = sd_ble_gatts_value_set (conn_handle, req->attr_handle , &value);
621
+ if (update_err) {
622
+ sd_ble_gatts_rw_authorize_reply (conn_handle, &write_auth_invalid_reply);
623
+ releaseLongWriteRequest (conn_handle);
624
+ return ;
625
+ }
626
+
627
+ sd_ble_gatts_rw_authorize_reply (conn_handle, &write_auth_succes_reply);
628
+
629
+ GattWriteCallbackParams writeParams = {
630
+ .connHandle = conn_handle,
631
+ .handle = req->attr_handle ,
632
+ .writeOp = static_cast <GattWriteCallbackParams::WriteOp_t>(input_req.op ),
633
+ .offset = req->offset ,
634
+ .len = req->length ,
635
+ .data = req->data ,
636
+ };
637
+ handleDataWrittenEvent (&writeParams);
638
+ releaseLongWriteRequest (conn_handle);
639
+ } return ;
640
+ }
641
+
454
642
GattWriteAuthCallbackParams cbParams = {
455
643
.connHandle = gattsEventP->conn_handle ,
456
644
.handle = handle_value,
@@ -541,3 +729,64 @@ void nRF5xGattServer::hwCallback(ble_evt_t *p_ble_evt)
541
729
break ;
542
730
}
543
731
}
732
+
733
+ uint16_t nRF5xGattServer::getBiggestCharacteristicSize () const {
734
+ uint16_t result = 0 ;
735
+ for (size_t i = 0 ; i < characteristicCount; ++i) {
736
+ uint16_t current_size = p_characteristics[i]->getValueAttribute ().getMaxLength ();
737
+ if (current_size > result) {
738
+ result = current_size;
739
+ }
740
+ }
741
+ return result;
742
+ }
743
+
744
+ nRF5xGattServer::long_write_request_t * nRF5xGattServer::allocateLongWriteRequest (uint16_t connection_handle) {
745
+ for (size_t i = 0 ; i < TOTAL_CONCURRENT_LONG_WRITE_REQUESTS; ++i) {
746
+ long_write_request_t & req = long_write_requests[i];
747
+ if (req.data == NULL ) {
748
+ uint16_t block_size = getBiggestCharacteristicSize ();
749
+ req.data = static_cast <uint8_t *>(malloc (block_size));
750
+ req.offset = 0 ;
751
+ req.length = 0 ;
752
+ req.conn_handle = connection_handle;
753
+ return &req;
754
+ }
755
+ }
756
+ // if nothing has been found then return null
757
+ return NULL ;
758
+ }
759
+
760
+ bool nRF5xGattServer::releaseLongWriteRequest (uint16_t connection_handle) {
761
+ long_write_request_t * req = findLongWriteRequest (connection_handle);
762
+ if (!req) {
763
+ return false ;
764
+ }
765
+
766
+ free (req->data );
767
+ req->data = NULL ;
768
+
769
+ // the other fields are not relevant, return now
770
+ return true ;
771
+ }
772
+
773
+ nRF5xGattServer::long_write_request_t * nRF5xGattServer::findLongWriteRequest (uint16_t connection_handle) {
774
+ for (size_t i = 0 ; i < TOTAL_CONCURRENT_LONG_WRITE_REQUESTS; ++i) {
775
+ long_write_request_t & req = long_write_requests[i];
776
+ if (req.data != NULL && req.conn_handle == connection_handle) {
777
+ return &req;
778
+ }
779
+ }
780
+ // if nothing has been found then return null
781
+ return NULL ;
782
+ }
783
+
784
+ void nRF5xGattServer::releaseAllWriteRequests () {
785
+ for (size_t i = 0 ; i < TOTAL_CONCURRENT_LONG_WRITE_REQUESTS; ++i) {
786
+ long_write_request_t & req = long_write_requests[i];
787
+ if (req.data != NULL ) {
788
+ free (req.data );
789
+ req.data = NULL ;
790
+ }
791
+ }
792
+ }
0 commit comments