libsigrok
|
00001 /* 00002 * This file is part of the sigrok project. 00003 * 00004 * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com> 00005 * 00006 * This program is free software: you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation, either version 3 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00018 */ 00019 00020 #include <stdlib.h> 00021 #include <stdint.h> 00022 #include <string.h> 00023 #include <glib.h> 00024 #include "sigrok.h" 00025 #include "sigrok-internal.h" 00026 00027 static gpointer new_chunk(struct sr_datastore **ds); 00028 00029 /** 00030 * Create a new datastore with the specified unit size. 00031 * 00032 * The unit size is fixed once the datastore is created, and cannot be 00033 * changed later on, neither can data be added to the datastore with 00034 * different unit sizes later. 00035 * 00036 * It is the caller's responsibility to free the allocated memory of the 00037 * datastore via the sr_datastore_destroy() function, if no longer needed. 00038 * 00039 * TODO: Unitsize should probably be unsigned int or uint32_t or similar. 00040 * TODO: This function should have a 'chunksize' parameter, and 00041 * struct sr_datastore a 'chunksize' field. 00042 * 00043 * @param unitsize The unit size (>= 1) to be used for this datastore. 00044 * @param ds Pointer to a variable which will hold the newly created 00045 * datastore structure. 00046 * 00047 * @return SR_OK upon success, SR_ERR_MALLOC upon memory allocation errors, 00048 * or SR_ERR_ARG upon invalid arguments. If something other than SR_OK 00049 * is returned, the value of 'ds' is undefined. 00050 */ 00051 SR_API int sr_datastore_new(int unitsize, struct sr_datastore **ds) 00052 { 00053 if (!ds) { 00054 sr_err("ds: %s: ds was NULL", __func__); 00055 return SR_ERR_ARG; 00056 } 00057 00058 if (unitsize <= 0) { 00059 sr_err("ds: %s: unitsize was %d, but it must be >= 1", 00060 __func__, unitsize); 00061 return SR_ERR_ARG; 00062 } 00063 00064 if (!(*ds = g_try_malloc(sizeof(struct sr_datastore)))) { 00065 sr_err("ds: %s: ds malloc failed", __func__); 00066 return SR_ERR_MALLOC; 00067 } 00068 00069 (*ds)->ds_unitsize = unitsize; 00070 (*ds)->num_units = 0; 00071 (*ds)->chunklist = NULL; 00072 00073 return SR_OK; 00074 } 00075 00076 /** 00077 * Destroy the specified datastore and free the memory used by it. 00078 * 00079 * This will free the memory used by the data in the datastore's 'chunklist', 00080 * by the chunklist data structure itself, and by the datastore struct. 00081 * 00082 * @param ds The datastore to destroy. 00083 * 00084 * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments. 00085 */ 00086 SR_API int sr_datastore_destroy(struct sr_datastore *ds) 00087 { 00088 GSList *chunk; 00089 00090 if (!ds) { 00091 sr_err("ds: %s: ds was NULL", __func__); 00092 return SR_ERR_ARG; 00093 } 00094 00095 for (chunk = ds->chunklist; chunk; chunk = chunk->next) 00096 g_free(chunk->data); 00097 g_slist_free(ds->chunklist); 00098 g_free(ds); 00099 ds = NULL; 00100 00101 return SR_OK; 00102 } 00103 00104 /** 00105 * Append some data to the specified datastore. 00106 * 00107 * TODO: More elaborate function description. 00108 * 00109 * TODO: This function should use the (not yet available) 'chunksize' field 00110 * of struct sr_datastore (instead of hardcoding DATASTORE_CHUNKSIZE). 00111 * TODO: in_unitsize and probelist are unused? 00112 * TODO: A few of the parameters can be const. 00113 * TODO: Ideally, 'ds' should be unmodified upon errors. 00114 * 00115 * @param ds Pointer to the datastore which shall receive the data. 00116 * Must not be NULL. 00117 * @param data Pointer to the memory buffer containing the data to add. 00118 * Must not be NULL. TODO: Data format? 00119 * @param length Length of the data to add (in number of bytes). 00120 * TODO: Should 0 be allowed as length? 00121 * @param in_unitsize The unit size (>= 1) of the input data. 00122 * @param probelist Pointer to a list of integers (probe numbers). The probe 00123 * numbers in this list are 1-based, i.e. the first probe 00124 * is expected to be numbered 1 (not 0!). Must not be NULL. 00125 * 00126 * @return SR_OK upon success, SR_ERR_MALLOC upon memory allocation errors, 00127 * or SR_ERR_ARG upon invalid arguments. If something other than SR_OK 00128 * is returned, the value/state of 'ds' is undefined. 00129 */ 00130 SR_API int sr_datastore_put(struct sr_datastore *ds, void *data, 00131 unsigned int length, int in_unitsize, const int *probelist) 00132 { 00133 unsigned int stored; 00134 int capacity, size, num_chunks, chunk_bytes_free, chunk_offset; 00135 gpointer chunk; 00136 00137 if (!ds) { 00138 sr_err("ds: %s: ds was NULL", __func__); 00139 return SR_ERR_ARG; 00140 } 00141 00142 /* Unitsize must not be 0, we'll divide by 0 otherwise. */ 00143 if (ds->ds_unitsize == 0) { 00144 sr_err("ds: %s: ds->ds_unitsize was 0", __func__); 00145 return SR_ERR_ARG; 00146 } 00147 00148 if (!data) { 00149 sr_err("ds: %s: data was NULL", __func__); 00150 return SR_ERR_ARG; 00151 } 00152 00153 if (in_unitsize < 1) { 00154 sr_err("ds: %s: in_unitsize was %d, but it must be >= 1", 00155 __func__, in_unitsize); 00156 return SR_ERR_ARG; 00157 } 00158 00159 if (!probelist) { 00160 sr_err("ds: %s: probelist was NULL", __func__); 00161 return SR_ERR_ARG; 00162 } 00163 00164 /* Get the last chunk in the list, or create a new one if needed. */ 00165 if (ds->chunklist == NULL) { 00166 if (!(chunk = new_chunk(&ds))) { 00167 sr_err("ds: %s: couldn't allocate new chunk", __func__); 00168 return SR_ERR_MALLOC; 00169 } 00170 } else { 00171 chunk = g_slist_last(ds->chunklist)->data; 00172 } 00173 00174 /* Get/calculate number of chunks, free space, etc. */ 00175 num_chunks = g_slist_length(ds->chunklist); 00176 capacity = (num_chunks * DATASTORE_CHUNKSIZE); 00177 chunk_bytes_free = capacity - (ds->ds_unitsize * ds->num_units); 00178 chunk_offset = capacity - (DATASTORE_CHUNKSIZE * (num_chunks - 1)) 00179 - chunk_bytes_free; 00180 00181 stored = 0; 00182 while (stored < length) { 00183 /* No more free space left, allocate a new chunk. */ 00184 if (chunk_bytes_free == 0) { 00185 if (!(chunk = new_chunk(&ds))) { 00186 sr_err("ds: %s: couldn't allocate new chunk", 00187 __func__); 00188 return SR_ERR_MALLOC; 00189 } 00190 chunk_bytes_free = DATASTORE_CHUNKSIZE; 00191 chunk_offset = 0; 00192 } 00193 00194 if (length - stored > (unsigned int)chunk_bytes_free) 00195 size = chunk_bytes_free; 00196 else 00197 /* Last part, won't fill up this chunk. */ 00198 size = length - stored; 00199 00200 memcpy(chunk + chunk_offset, data + stored, size); 00201 chunk_bytes_free -= size; 00202 stored += size; 00203 } 00204 00205 ds->num_units += stored / ds->ds_unitsize; 00206 00207 return SR_OK; 00208 } 00209 00210 /** 00211 * Allocate a new memory chunk, append it to the datastore's chunklist. 00212 * 00213 * The newly allocated chunk is added to the datastore's chunklist by this 00214 * function, and the return value additionally points to the new chunk. 00215 * 00216 * The allocated memory is guaranteed to be cleared. 00217 * 00218 * TODO: This function should use the datastore's 'chunksize' field instead 00219 * of hardcoding DATASTORE_CHUNKSIZE. 00220 * TODO: Return int, so we can return SR_OK / SR_ERR_ARG / SR_ERR_MALLOC? 00221 * 00222 * @param ds Pointer to a variable which holds the datastore structure. 00223 * Must not be NULL. The contents of 'ds' are modified in-place. 00224 * 00225 * @return Pointer to the newly allocated chunk, or NULL upon failure. 00226 */ 00227 static gpointer new_chunk(struct sr_datastore **ds) 00228 { 00229 gpointer chunk; 00230 00231 /* Note: Caller checked that ds != NULL. */ 00232 00233 chunk = g_try_malloc0(DATASTORE_CHUNKSIZE * (*ds)->ds_unitsize); 00234 if (!chunk) { 00235 sr_err("ds: %s: chunk malloc failed", __func__); 00236 return NULL; /* TODO: SR_ERR_MALLOC later? */ 00237 } 00238 00239 (*ds)->chunklist = g_slist_append((*ds)->chunklist, chunk); 00240 00241 return chunk; /* TODO: SR_OK later? */ 00242 }