uint8_t pm_buffer_block_acquire(pm_buffer_t * p_buffer, uint32_t n_blocks) { if (!BUFFER_IS_VALID(p_buffer)) { return ( BUFFER_INVALID_ID ); } uint8_t first_locked_mutex = BUFFER_INVALID_ID; for (uint8_t i = 0; i < p_buffer->n_blocks; i++) { if (pm_mutex_lock(p_buffer->p_mutex, i)) { if (first_locked_mutex == BUFFER_INVALID_ID) { first_locked_mutex = i; } if ((i - first_locked_mutex + 1) == n_blocks) { return first_locked_mutex; } } else if (first_locked_mutex != BUFFER_INVALID_ID) { for (uint8_t j = first_locked_mutex; j < i; j++) { pm_buffer_release(p_buffer, j); } first_locked_mutex = BUFFER_INVALID_ID; } } return ( BUFFER_INVALID_ID ); }
/**@brief Function for gracefully deactivating a write buffer record. * * @details This function will first release any buffers, then invalidate the record. * * @param[inout] p_write_buffer_record The record to release. * * @return A pointer to the matching record, or NULL if none was found. */ static void write_buffer_record_release(pdb_buffer_record_t * p_write_buffer_record) { for (int i = 0; i < p_write_buffer_record->n_bufs; i++) { pm_buffer_release(&m_pdb.write_buffer, p_write_buffer_record->buffer_block_id + i); } write_buffer_record_invalidate(p_write_buffer_record); }
ret_code_t pdb_write_buf_get(pm_peer_id_t peer_id, pm_peer_data_id_t data_id, uint32_t n_bufs, pm_peer_data_t * p_peer_data) { VERIFY_MODULE_INITIALIZED(); VERIFY_PARAM_NOT_NULL(p_peer_data); if ( !PM_PEER_DATA_ID_IS_VALID(data_id) || (n_bufs == 0) || (n_bufs > N_WRITE_BUFFERS) || !pds_peer_id_is_allocated(peer_id)) { return NRF_ERROR_INVALID_PARAM; } pdb_buffer_record_t * write_buffer_record; uint8_t * p_buffer_memory; write_buffer_record = write_buffer_record_find(peer_id, data_id); if ((write_buffer_record != NULL) && (write_buffer_record->n_bufs < n_bufs)) { // @TODO: Copy? // Existing buffer is too small. for (uint8_t i = 0; i < write_buffer_record->n_bufs; i++) { pm_buffer_release(&m_pdb.write_buffer, write_buffer_record->buffer_block_id + i); } write_buffer_record_invalidate(write_buffer_record); write_buffer_record = NULL; } else if ((write_buffer_record != NULL) && write_buffer_record->n_bufs > n_bufs) { // Release excess blocks. for (uint8_t i = n_bufs; i < write_buffer_record->n_bufs; i++) { pm_buffer_release(&m_pdb.write_buffer, write_buffer_record->buffer_block_id + i); } } if (write_buffer_record == NULL) { write_buffer_record_get(&write_buffer_record, peer_id, data_id); if (write_buffer_record == NULL) { return NRF_ERROR_BUSY; } } if (write_buffer_record->buffer_block_id == BUFFER_INVALID_ID) { write_buffer_record->buffer_block_id = pm_buffer_block_acquire(&m_pdb.write_buffer, n_bufs); if (write_buffer_record->buffer_block_id == BUFFER_INVALID_ID) { write_buffer_record_invalidate(write_buffer_record); return NRF_ERROR_BUSY; } } write_buffer_record->n_bufs = n_bufs; p_buffer_memory = pm_buffer_ptr_get(&m_pdb.write_buffer, write_buffer_record->buffer_block_id); if (p_buffer_memory == NULL) { return NRF_ERROR_INTERNAL; } peer_data_point_to_buffer(p_peer_data, data_id, p_buffer_memory, n_bufs); switch(data_id) { case PM_PEER_DATA_ID_BONDING: /* No action needed. */ break; case PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING: /* No action needed. */ break; case PM_PEER_DATA_ID_GATT_LOCAL: { uint32_t size_offset = sizeof(pm_peer_data_local_gatt_db_t); p_peer_data->data.p_local_gatt_db->p_data = &p_buffer_memory[size_offset]; p_peer_data->data.p_local_gatt_db->len = (PDB_WRITE_BUF_SIZE*n_bufs)-size_offset; } break; case PM_PEER_DATA_ID_GATT_REMOTE: { uint32_t size_offset = sizeof(pm_peer_data_remote_gatt_db_t); p_peer_data->data.p_remote_gatt_db->p_data = (ble_gatt_db_srv_t*)&(p_buffer_memory[size_offset]); p_peer_data->data.p_remote_gatt_db->service_count = ((PDB_WRITE_BUF_SIZE*n_bufs)-size_offset)/sizeof(ble_gatt_db_srv_t); } break; case PM_PEER_DATA_ID_APPLICATION: { p_peer_data->data.p_application_data = p_buffer_memory; } break; default: // Invalid data_id. This should have been picked up earlier. return NRF_ERROR_INTERNAL; } return NRF_SUCCESS; }