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,140 @@ 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
+ releaseLongWriteRequest (conn_handle);
536
+ return ;
537
+ }
538
+
539
+ // initialize the first request by setting the offset
540
+ if (req->length == 0 ) {
541
+ req->attr_handle = input_req.handle ;
542
+ req->offset = input_req.offset ;
543
+ }
544
+
545
+ // it is disalowed to write backward
546
+ if (input_req.offset < req->offset ) {
547
+ sd_ble_gatts_rw_authorize_reply (conn_handle, &write_auth_invalid_offset_reply);
548
+ releaseLongWriteRequest (conn_handle);
549
+ return ;
550
+ }
551
+
552
+ // it should be the subsequent write
553
+ if ((req->offset + req->length ) != input_req.offset ) {
554
+ sd_ble_gatts_rw_authorize_reply (conn_handle, &write_auth_invalid_offset_reply);
555
+ releaseLongWriteRequest (conn_handle);
556
+ return ;
557
+ }
558
+
559
+ // it is not allowed to write multiple characteristic with the same request
560
+ if (input_req.handle != req->attr_handle ) {
561
+ sd_ble_gatts_rw_authorize_reply (conn_handle, &write_auth_invalid_reply);
562
+ releaseLongWriteRequest (conn_handle);
563
+ return ;
564
+ }
565
+
566
+ // start the copy of what is in input
567
+ memcpy (req->data + req->length , input_req.data , input_req.len );
568
+
569
+ // update the lenght of the data written
570
+ req->length = req->length + input_req.len ;
571
+
572
+ // success, signal it to the softdevice
573
+ ble_gatts_rw_authorize_reply_params_t reply = {
574
+ .type = BLE_GATTS_AUTHORIZE_TYPE_WRITE,
575
+ .params = {
576
+ .write = {
577
+ .gatt_status = BLE_GATT_STATUS_SUCCESS,
578
+ .update = 1 ,
579
+ .offset = input_req.offset ,
580
+ .len = input_req.len ,
581
+ .p_data = input_req.data
582
+ }
583
+ }
584
+ };
585
+
586
+ sd_ble_gatts_rw_authorize_reply (conn_handle, &reply);
587
+ } return ;
588
+
589
+ case BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL: {
590
+ releaseLongWriteRequest (conn_handle);
591
+ sd_ble_gatts_rw_authorize_reply (conn_handle, &write_auth_succes_reply);
592
+ } return ;
593
+
594
+ case BLE_GATTS_OP_EXEC_WRITE_REQ_NOW: {
595
+ long_write_request_t * req = findLongWriteRequest (conn_handle);
596
+ if (!req) {
597
+ sd_ble_gatts_rw_authorize_reply (conn_handle, &write_auth_invalid_reply);
598
+ releaseLongWriteRequest (conn_handle);
599
+ return ;
600
+ }
601
+
602
+ GattWriteAuthCallbackParams cbParams = {
603
+ .connHandle = conn_handle,
604
+ .handle = req->attr_handle ,
605
+ .offset = req->offset ,
606
+ .len = req->length ,
607
+ .data = req->data ,
608
+ .authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS /* the callback handler must leave this member
609
+ * set to AUTH_CALLBACK_REPLY_SUCCESS if the client
610
+ * request is to proceed. */
611
+ };
612
+ uint16_t write_authorization = p_characteristics[characteristicIndex]->authorizeWrite (&cbParams);
613
+
614
+ // the user code didn't provide the write authorization,
615
+ // just leave here.
616
+ if (write_authorization != AUTH_CALLBACK_REPLY_SUCCESS) {
617
+ // report the status of the operation in any cases
618
+ sd_ble_gatts_rw_authorize_reply (gattsEventP->conn_handle , &write_auth_invalid_reply);
619
+ releaseLongWriteRequest (conn_handle);
620
+ return ;
621
+ }
622
+
623
+ // FIXME can't use ::write here, this function doesn't take the offset into account ...
624
+ ble_gatts_value_t value = {
625
+ .len = req->length ,
626
+ .offset = req->offset ,
627
+ .p_value = req->data
628
+ };
629
+ uint32_t update_err = sd_ble_gatts_value_set (conn_handle, req->attr_handle , &value);
630
+ if (update_err) {
631
+ sd_ble_gatts_rw_authorize_reply (conn_handle, &write_auth_invalid_reply);
632
+ releaseLongWriteRequest (conn_handle);
633
+ return ;
634
+ }
635
+
636
+ sd_ble_gatts_rw_authorize_reply (gattsEventP->conn_handle , &write_auth_succes_reply);
637
+
638
+ GattWriteCallbackParams writeParams = {
639
+ .connHandle = conn_handle,
640
+ .handle = req->attr_handle ,
641
+ .writeOp = static_cast <GattWriteCallbackParams::WriteOp_t>(input_req.op ),
642
+ .offset = req->offset ,
643
+ .len = req->length ,
644
+ .data = req->data ,
645
+ };
646
+ handleDataWrittenEvent (&writeParams);
647
+ releaseLongWriteRequest (conn_handle);
648
+ } return ;
649
+ }
650
+
454
651
GattWriteAuthCallbackParams cbParams = {
455
652
.connHandle = gattsEventP->conn_handle ,
456
653
.handle = handle_value,
@@ -541,3 +738,64 @@ void nRF5xGattServer::hwCallback(ble_evt_t *p_ble_evt)
541
738
break ;
542
739
}
543
740
}
741
+
742
+ uint16_t nRF5xGattServer::getBiggestCharacteristicSize () const {
743
+ uint16_t result = 0 ;
744
+ for (size_t i = 0 ; i < characteristicCount; ++i) {
745
+ uint16_t current_size = p_characteristics[i]->getValueAttribute ().getMaxLength ();
746
+ if (current_size > result) {
747
+ result = current_size;
748
+ }
749
+ }
750
+ return result;
751
+ }
752
+
753
+ nRF5xGattServer::long_write_request_t * nRF5xGattServer::allocateLongWriteRequest (uint16_t connection_handle) {
754
+ for (size_t i = 0 ; i < TOTAL_CONCURENT_LONG_WRITE_REQUEST; ++i) {
755
+ long_write_request_t & req = long_write_requests[i];
756
+ if (req.data == NULL ) {
757
+ uint16_t block_size = getBiggestCharacteristicSize ();
758
+ req.data = static_cast <uint8_t *>(malloc (block_size));
759
+ req.offset = 0 ;
760
+ req.length = 0 ;
761
+ req.conn_handle = connection_handle;
762
+ return &req;
763
+ }
764
+ }
765
+ // if nothing has been found then return null
766
+ return NULL ;
767
+ }
768
+
769
+ bool nRF5xGattServer::releaseLongWriteRequest (uint16_t connection_handle) {
770
+ long_write_request_t * req = findLongWriteRequest (connection_handle);
771
+ if (!req) {
772
+ return false ;
773
+ }
774
+
775
+ free (req->data );
776
+ req->data = NULL ;
777
+
778
+ // the other fields are not relevant, return now
779
+ return true ;
780
+ }
781
+
782
+ nRF5xGattServer::long_write_request_t * nRF5xGattServer::findLongWriteRequest (uint16_t connection_handle) {
783
+ for (size_t i = 0 ; i < TOTAL_CONCURENT_LONG_WRITE_REQUEST; ++i) {
784
+ long_write_request_t & req = long_write_requests[i];
785
+ if (req.data != NULL && req.conn_handle == connection_handle) {
786
+ return &req;
787
+ }
788
+ }
789
+ // if nothing has been found then return null
790
+ return NULL ;
791
+ }
792
+
793
+ void nRF5xGattServer::releaseAllWriteRequests () {
794
+ for (size_t i = 0 ; i < TOTAL_CONCURENT_LONG_WRITE_REQUEST; ++i) {
795
+ long_write_request_t & req = long_write_requests[i];
796
+ if (req.data != NULL ) {
797
+ free (req.data );
798
+ req.data = NULL ;
799
+ }
800
+ }
801
+ }
0 commit comments