scpr_device.c (4766B)
1 /* Copyright (C) 2016-2018, 2021-2024 |Méso|Star> (contact@meso-star.com) 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #include "scpr.h" 17 #include "scpr_c.h" 18 19 #include <polygon.h> 20 #include <rsys/mem_allocator.h> 21 #include <rsys/logger.h> 22 #include <rsys/rsys.h> 23 #include <rsys/double2.h> 24 25 #include <math.h> 26 27 #ifdef OS_UNIX 28 /* On UNIX assume a VT100-like terminal emulator */ 29 #define MSG_INFO_PREFIX "star-cpr (\x1b[1m\x1b[32minfo\x1b[0m): " 30 #define MSG_ERROR_PREFIX "star-cpr (\x1b[1m\x1b[31merror\x1b[0m): " 31 #define MSG_WARNING_PREFIX "star-cpr (\x1b[1m\x1b[33mwarning\x1b[0m): " 32 #else 33 #define MSG_INFO_PREFIX "star-cpr (info): " 34 #define MSG_ERROR_PREFIX "star-cpr (error): " 35 #define MSG_WARNING_PREFIX "star-cpr (warning): " 36 #endif 37 38 /******************************************************************************* 39 * Helper functions 40 ******************************************************************************/ 41 static void 42 device_release(ref_T* ref) 43 { 44 struct scpr_device* device; 45 struct mem_allocator* allocator; 46 ASSERT(ref); 47 device = CONTAINER_OF(ref, struct scpr_device, ref); 48 allocator = device->allocator; 49 MEM_RM(allocator, device); 50 } 51 52 int INLINE 53 is_in_range 54 (const double x, 55 const double range[2]) 56 { 57 ASSERT(range); 58 return range[0] <= x && x <= range[1]; 59 } 60 61 /******************************************************************************* 62 * Exported functions 63 ******************************************************************************/ 64 res_T 65 scpr_device_create 66 (const struct scpr_device_create_args* args, 67 struct scpr_device** out_device) 68 { 69 struct scpr_device* device = NULL; 70 struct mem_allocator* allocator = NULL; 71 res_T res = RES_OK; 72 73 if(!args || !out_device || args->precision < 0 || args->precision > 8) { 74 res = RES_BAD_ARG; 75 goto error; 76 } 77 78 allocator = args->allocator ? args->allocator : &mem_default_allocator; 79 device = (struct scpr_device*)MEM_CALLOC(allocator, 1, sizeof(struct scpr_device)); 80 if(!device) { 81 res = RES_MEM_ERR; 82 goto error; 83 } 84 ref_init(&device->ref); 85 device->allocator = allocator; 86 device->logger = args->logger ? args->logger : LOGGER_DEFAULT; 87 device->precision = args->precision; 88 /* to optimize scaling / descaling precision 89 * set the scale to a power of double's radix (2) (#25) */ 90 device->scale = pow(2, (int)log2(pow(10, device->precision)) + 1); 91 device->inv_scale = 1/device->scale; 92 device->range[1] = pow(2, 46 - device->precision); 93 device->range[0] = -device->range[1]; 94 95 exit: 96 if(out_device) *out_device = device; 97 return res; 98 99 error: 100 if(device) { 101 SCPR(device_ref_put(device)); 102 device = NULL; 103 } 104 goto exit; 105 } 106 107 res_T 108 scpr_device_ref_get 109 (struct scpr_device* device) 110 { 111 if(!device) return RES_BAD_ARG; 112 ref_get(&device->ref); 113 return RES_OK; 114 } 115 116 res_T 117 scpr_device_ref_put 118 (struct scpr_device* device) 119 { 120 if(!device) return RES_BAD_ARG; 121 ref_put(&device->ref, device_release); 122 return RES_OK; 123 } 124 125 res_T 126 scpr_device_get_range 127 (const struct scpr_device* dev, 128 double range[2]) 129 { 130 if(!dev || !range) return RES_BAD_ARG; 131 d2_set(range, dev->range); 132 return RES_OK; 133 } 134 135 res_T 136 scpr_device_in_range 137 (const struct scpr_device* dev, 138 const double* values, 139 const size_t count, 140 int* in_range) 141 142 { 143 size_t i; 144 int in = 1; 145 if(!dev || !values || !in_range) return RES_BAD_ARG; 146 for(i = 0; i < count; i++) { 147 if(!is_in_range(values[i], dev->range)) { 148 in = 0; 149 break; 150 } 151 } 152 *in_range = in; 153 return RES_OK; 154 } 155 156 res_T 157 scpr_device_scale 158 (const struct scpr_device* dev, 159 const double* values, 160 const size_t count, 161 int64_t* scaled) 162 { 163 size_t i; 164 if(!dev || !values || !scaled) return RES_BAD_ARG; 165 for(i = 0; i < count; i++) { 166 if(!is_in_range(values[i], dev->range)) return RES_BAD_ARG; 167 scaled[i] = std::llround(values[i] * dev->scale); 168 } 169 return RES_OK; 170 } 171 172 res_T 173 scpr_device_unscale 174 (const struct scpr_device* dev, 175 const int64_t* values, 176 const size_t count, 177 double* unscaled) 178 { 179 size_t i; 180 if(!dev || !values || !unscaled) return RES_BAD_ARG; 181 for(i = 0; i < count; i++) { 182 unscaled[i] = (double)values[i] * dev->inv_scale; 183 } 184 return RES_OK; 185 }