This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nRF51: writing to a characteristic

Hello,

I am using SD 130 on nRF5 with SDK V12.1.0.

I want to write to a characteristic using the android debug app (nrf connect).

This is my code for the characteristic:

  ble_uuid_t          char_uuid;
  char_uuid.uuid      = BLE_UUID_MY_CHARACTERISTC_UUID;
  err_code = sd_ble_uuid_vs_add(&base_uuid, &char_uuid.type);
  APP_ERROR_CHECK(err_code);



  ble_gatts_attr_md_t attr_md;
  memset(&attr_md, 0, sizeof(attr_md));
  attr_md.vloc        = BLE_GATTS_VLOC_STACK;              
  BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);       
  BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);      

  /* Characteristic Value Attribute  */
  ble_gatts_attr_t    attr_char_value;

  memset(&attr_char_value, 0, sizeof(attr_char_value));   
  attr_char_value.p_uuid      = &char_uuid;
  attr_char_value.p_attr_md   = &attr_md;                     /* assign attribute metadata to characteristic value attribute */
  attr_char_value.max_len     = 1;                            /* max value length */
  attr_char_value.init_len    = 1;                            /* initial value length */
  attr_char_value.p_value = (uint8_t*)&MyVar;                            /* ptr to actual value */


  ble_gatts_char_md_t char_md;
  memset(&char_md, 0, sizeof(char_md));
  char_md.char_props.read = 1;                                /* set read property */
  char_md.char_props.write = 1;                               /* set write proper */
  

  err_code = sd_ble_gatts_characteristic_add(p_our_service->service_handle,
                                     &char_md,
                                     &attr_char_value,
                                     &p_our_service->char_handles_dry);
  APP_ERROR_CHECK(err_code);

What is happening: I can write a value to the characteristic. When I read it afterwards, it is correct. BUT: The debugger shows me, that MyVar did not change.

Question 1: Where is the new value saved? It's obviously not in MyVar as I assumed.

Question 2: How can I update MyVar with the correct value?

Thank you very much in advance!

Regards

  • The code you show above will just setup the characteristic. You need to handle the writing of the value in the on_write function which is normally called by the on ble evt handler. The value might be wriiten to the stack by default which might be why you are able to read it back correctly. If you handle the on write for your char then you should be able to set the value of myvar.

  • Thank you very much for your answer. I made the mentioned changes and it works so far:

    static void on_write(ble_soil_t * p_bas, ble_evt_t * p_ble_evt)
    {
      ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
      
      if (p_evt_write->handle == p_bas->char_handles_dry.value_handle)
      {  
        
        if(CALIB_TRIGGER == *p_evt_write->data)
        {
          SoilMoistureThresholdDry = SoilMoistureValue;
        }
      }
               
      
    }
    void ble_soil_on_ble_evt(ble_soil_t * p_our_service, ble_evt_t * p_ble_evt)
    {
      /* Connection status handle updaten*/
      switch (p_ble_evt->header.evt_id)
      {
        case BLE_GAP_EVT_CONNECTED:
            p_our_service->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
            break;
        case BLE_GAP_EVT_DISCONNECTED:
            p_our_service->conn_handle = BLE_CONN_HANDLE_INVALID;
            break;
        case BLE_GATTS_EVT_WRITE:
            on_write(p_our_service, p_ble_evt);
            break;
        default:
            // No implementation needed.
            break;
      }
    
    }
    

    1. Question As you can see, I want the characteristic variable to be updated when a special number is written to it (calibration trigger, e.g. "1"). It works fine in the debugger, the variable is updated correctly (SoilMoistureThresholdDry is also the variable connected to the characteristic I have written to, it should work like this: write CALIB_TRIGGER to characteristic, but don't update the connected variable with this value but update it with another value). But when I read the value again in NRF connect, it stills shows the value I have written before and not the updated value. I assume this has also todo with the stack. How can I tell the Softdevice to update the stack with the new value?

    2. Question When searching the forum I often found solutions which implemented a write_handler, e.g.

    static void on_write(ble_dls_t * p_dls, ble_evt_t * p_ble_evt)
    {
        ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
            uint32_t temp_val = 0;
    
        if ((p_evt_write->handle == p_dls->dl_char_handles.value_handle) &&
            (p_evt_write->len == 4) &&
            (p_dls->dl_write_handler != NULL))
        {
                    p_dls->dl_write_handler(p_dls, p_evt_write);
        }
    
    }
    

    Can you tell me how to implement such a write handler?

    Thank you very much for your support!

    Regards

  • You are setting the vloc attribute to BLE_GATTS_VLOC_STACK. This will located the value in stack memory. Try changing this to BLE_GATTS_VLOC_USER, to locate the value in user memory. Notice that this requires you maintain a valid buffer through the lifetime of the attribute, since the stack will read and write directly to the memory using the pointer provided in the APIs.

  • Jorgen is correct. Sorry I overlook that aspect. Not sure why since I mentioned that the variable was on the stack by default. If you make the change as Jorgen has pointed out I don't believe you will need to manage the variable explicitly. Just need to make sure MyVar buffer persist and can hold the data.

Related