File indexing completed on 2025-05-11 08:24:18
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034 #include <stdlib.h>
0035
0036 #include <rtems.h>
0037 #include <rtems/regulator.h>
0038 #include <string.h>
0039
0040 #include <rtems/regulatorimpl.h>
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054 static rtems_task _Regulator_Output_task_body(
0055 rtems_task_argument arg
0056 )
0057 {
0058 _Regulator_Control *the_regulator = (_Regulator_Control *)arg;
0059 rtems_status_code sc;
0060 size_t to_dequeue;
0061 _Regulator_Message_t regulator_message;
0062 size_t regulator_message_size;
0063 bool release_it;
0064
0065 the_regulator->delivery_thread_is_running = true;
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079 sc = rtems_rate_monotonic_create(
0080 rtems_build_name('P', 'E', 'R', 'D'),
0081 &the_regulator->delivery_thread_period_id
0082 );
0083 if (sc != RTEMS_SUCCESSFUL) {
0084 goto exit_delivery_thread;
0085 }
0086
0087
0088
0089
0090 while (1) {
0091 sc = rtems_rate_monotonic_period(
0092 the_regulator->delivery_thread_period_id,
0093 the_regulator->Attributes.delivery_thread_period
0094 );
0095 _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL);
0096
0097
0098
0099
0100
0101
0102 if (the_regulator->delivery_thread_request_exit) {
0103 break;
0104 }
0105
0106
0107
0108
0109
0110
0111 for (to_dequeue = 0;
0112 to_dequeue < the_regulator->Attributes.maximum_to_dequeue_per_period;
0113 to_dequeue++) {
0114 regulator_message_size = sizeof(_Regulator_Message_t);
0115 sc = rtems_message_queue_receive(
0116 the_regulator->queue_id,
0117 ®ulator_message,
0118 ®ulator_message_size,
0119 RTEMS_NO_WAIT,
0120 0
0121 );
0122 _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL);
0123 if (sc != RTEMS_SUCCESSFUL) {
0124 break;
0125 }
0126
0127 release_it = the_regulator->Attributes.deliverer(
0128 the_regulator->Attributes.deliverer_context,
0129 regulator_message.buffer,
0130 regulator_message.length
0131 );
0132
0133 the_regulator->Statistics.delivered++;
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145 if (release_it == true) {
0146 the_regulator->Statistics.released++;
0147 sc = rtems_partition_return_buffer(
0148 the_regulator->messages_partition_id,
0149 regulator_message.buffer
0150 );
0151 _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL);
0152 }
0153 }
0154 }
0155
0156
0157
0158
0159 exit_delivery_thread:
0160 the_regulator->delivery_thread_is_running = false;
0161 the_regulator->delivery_thread_has_exited = true;
0162
0163 (void) rtems_rate_monotonic_delete(the_regulator->delivery_thread_period_id);
0164
0165 rtems_task_exit();
0166 }
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182 static bool _Regulator_Free_helper(
0183 _Regulator_Control *the_regulator,
0184 rtems_interval ticks
0185 )
0186 {
0187 rtems_status_code sc;
0188
0189
0190
0191
0192
0193
0194 if (ticks == 0 || the_regulator->delivery_thread_is_running == false) {
0195 sc = rtems_task_delete(the_regulator->delivery_thread_id);
0196 _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL);
0197 } else {
0198 rtems_interval remaining = ticks;
0199
0200 the_regulator->delivery_thread_request_exit = true;
0201
0202 while (1) {
0203 if (the_regulator->delivery_thread_has_exited) {
0204 break;
0205 }
0206
0207 if (remaining == 0) {
0208 return false;
0209 }
0210
0211 (void) rtems_task_wake_after(1);
0212 remaining--;
0213 }
0214 }
0215
0216
0217
0218
0219
0220
0221
0222
0223 sc = rtems_message_queue_delete(the_regulator->queue_id);
0224 _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL);
0225
0226 sc = rtems_partition_delete(the_regulator->messages_partition_id);
0227 _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL);
0228
0229 if (the_regulator->message_memory) {
0230 free(the_regulator->message_memory);
0231 }
0232
0233 the_regulator->initialized = 0;
0234 free(the_regulator);
0235 return true;
0236 }
0237
0238
0239
0240
0241 rtems_status_code rtems_regulator_create(
0242 rtems_regulator_attributes *attributes,
0243 rtems_regulator_instance **regulator
0244 )
0245 {
0246 _Regulator_Control *the_regulator;
0247 rtems_status_code sc;
0248 size_t alloc_size;
0249
0250
0251
0252
0253 if (attributes == NULL) {
0254 return RTEMS_INVALID_ADDRESS;
0255 }
0256
0257 if (regulator == NULL) {
0258 return RTEMS_INVALID_ADDRESS;
0259 }
0260
0261
0262
0263
0264
0265
0266
0267
0268 if (attributes->deliverer == NULL) {
0269 return RTEMS_INVALID_ADDRESS;
0270 }
0271
0272 if (attributes->maximum_messages == 0) {
0273 return RTEMS_INVALID_NUMBER;
0274 }
0275
0276 if (attributes->maximum_message_size == 0) {
0277 return RTEMS_INVALID_SIZE;
0278 }
0279
0280 if (attributes->maximum_to_dequeue_per_period == 0) {
0281 return RTEMS_INVALID_NUMBER;
0282 }
0283
0284 if (attributes->delivery_thread_period == 0) {
0285 return RTEMS_INVALID_NUMBER;
0286 }
0287
0288
0289
0290
0291 the_regulator = (_Regulator_Control *) calloc(sizeof(_Regulator_Control), 1);
0292 if (the_regulator == NULL) {
0293 return RTEMS_NO_MEMORY;
0294 }
0295
0296
0297
0298
0299
0300
0301
0302
0303 the_regulator->delivery_thread_id = (rtems_id) -1;
0304
0305
0306
0307
0308 the_regulator->Attributes = *attributes;
0309
0310
0311
0312
0313
0314 alloc_size = attributes->maximum_message_size * attributes->maximum_messages;
0315 the_regulator->message_memory = calloc(alloc_size, 1);
0316 if (the_regulator->message_memory == NULL) {
0317 _Regulator_Free_helper(the_regulator, 0);
0318 return RTEMS_NO_MEMORY;
0319 }
0320
0321
0322
0323
0324 sc = rtems_partition_create(
0325 rtems_build_name('P', 'O', 'O', 'L'),
0326 the_regulator->message_memory,
0327 alloc_size,
0328 attributes->maximum_message_size,
0329 RTEMS_DEFAULT_ATTRIBUTES,
0330 &the_regulator->messages_partition_id
0331 );
0332 if (sc != RTEMS_SUCCESSFUL) {
0333 _Regulator_Free_helper(the_regulator, 0);
0334 return sc;
0335 }
0336
0337
0338
0339
0340 RTEMS_MESSAGE_QUEUE_BUFFER(sizeof(_Regulator_Message_t)) regulator_message_t;
0341
0342 size_t storage_size = sizeof(regulator_message_t) * attributes->maximum_messages;
0343
0344 the_regulator->message_queue_storage = malloc(storage_size);
0345 if (the_regulator->message_queue_storage == NULL) {
0346 _Regulator_Free_helper(the_regulator, 0);
0347 return RTEMS_NO_MEMORY;
0348 }
0349
0350 rtems_message_queue_config mq_config = {
0351 .name = rtems_build_name('S', 'N', 'D', 'Q'),
0352 .maximum_pending_messages = attributes->maximum_messages,
0353 .maximum_message_size = sizeof(_Regulator_Message_t),
0354 .storage_area = the_regulator->message_queue_storage,
0355 .storage_size = storage_size,
0356 .storage_free = free,
0357 .attributes = RTEMS_DEFAULT_ATTRIBUTES
0358 };
0359 sc = rtems_message_queue_construct(
0360 &mq_config,
0361 &the_regulator->queue_id
0362 );
0363 if (sc != RTEMS_SUCCESSFUL) {
0364 _Regulator_Free_helper(the_regulator, 0);
0365 return sc;
0366 }
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378 sc = rtems_task_create(
0379 rtems_build_name('R', 'E', 'G', 'U'),
0380 attributes->delivery_thread_priority,
0381 attributes->delivery_thread_stack_size,
0382 RTEMS_DEFAULT_MODES,
0383 RTEMS_DEFAULT_ATTRIBUTES,
0384 &the_regulator->delivery_thread_id
0385 );
0386 if (sc != RTEMS_SUCCESSFUL) {
0387 _Regulator_Free_helper(the_regulator, 0);
0388 return sc;
0389 }
0390
0391
0392
0393
0394
0395
0396
0397
0398 the_regulator->delivery_thread_is_running = true;
0399 the_regulator->delivery_thread_request_exit = false;
0400 the_regulator->delivery_thread_has_exited = false;
0401
0402 sc = rtems_task_start(
0403 the_regulator->delivery_thread_id,
0404 _Regulator_Output_task_body,
0405 (rtems_task_argument) the_regulator
0406 );
0407 _Assert_Unused_variable_equals(sc, RTEMS_SUCCESSFUL);
0408
0409
0410
0411
0412
0413 the_regulator->initialized = REGULATOR_INITIALIZED;
0414
0415 *regulator = (void *)the_regulator;
0416
0417 return RTEMS_SUCCESSFUL;
0418 }
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432 static inline _Regulator_Control *_Regulator_Get(
0433 rtems_regulator_instance *regulator,
0434 rtems_status_code *status
0435 )
0436 {
0437 _Regulator_Control *the_regulator = (_Regulator_Control *) regulator;
0438
0439 if (the_regulator == NULL) {
0440 *status = RTEMS_INVALID_ADDRESS;
0441 return NULL;
0442 }
0443
0444 if (the_regulator->initialized != REGULATOR_INITIALIZED) {
0445 *status = RTEMS_INCORRECT_STATE;
0446 return NULL;
0447 }
0448
0449 status = RTEMS_SUCCESSFUL;
0450 return the_regulator;
0451 }
0452
0453
0454
0455
0456 rtems_status_code rtems_regulator_delete(
0457 rtems_regulator_instance *regulator,
0458 rtems_interval ticks
0459 )
0460 {
0461 _Regulator_Control *the_regulator;
0462 rtems_status_code status;
0463
0464
0465
0466
0467 the_regulator = _Regulator_Get(regulator, &status);
0468 if (the_regulator == NULL) {
0469 return status;
0470 }
0471
0472
0473
0474
0475 _Regulator_Statistics *stats = &the_regulator->Statistics;
0476
0477 if (stats->obtained != stats->released ) {
0478 return RTEMS_RESOURCE_IN_USE;
0479 }
0480
0481
0482
0483
0484 bool bc;
0485 bc = _Regulator_Free_helper(the_regulator, ticks);
0486 if (bc == false) {
0487 return RTEMS_TIMEOUT;
0488 }
0489
0490 return RTEMS_SUCCESSFUL;
0491 }
0492
0493
0494
0495
0496
0497
0498 rtems_status_code rtems_regulator_obtain_buffer(
0499 rtems_regulator_instance *regulator,
0500 void **buffer
0501 )
0502 {
0503 _Regulator_Control *the_regulator;
0504 rtems_status_code status;
0505
0506
0507
0508
0509 the_regulator = _Regulator_Get(regulator, &status);
0510 if (the_regulator == NULL) {
0511 return status;
0512 }
0513
0514
0515
0516
0517
0518 status = rtems_partition_get_buffer(
0519 the_regulator->messages_partition_id,
0520 buffer
0521 );
0522
0523 if (status == RTEMS_SUCCESSFUL) {
0524 the_regulator->Statistics.obtained++;
0525 }
0526
0527 return status;
0528 }
0529
0530
0531
0532
0533
0534
0535 rtems_status_code rtems_regulator_release_buffer(
0536 rtems_regulator_instance *regulator,
0537 void *buffer
0538 )
0539 {
0540 _Regulator_Control *the_regulator;
0541 rtems_status_code status;
0542
0543
0544
0545
0546 the_regulator = _Regulator_Get(regulator, &status);
0547 if (the_regulator == NULL) {
0548 return status;
0549 }
0550
0551
0552
0553
0554
0555 status = rtems_partition_return_buffer(
0556 the_regulator->messages_partition_id,
0557 buffer
0558 );
0559
0560 if (status == RTEMS_SUCCESSFUL) {
0561 the_regulator->Statistics.released++;
0562 }
0563
0564 return status;
0565 }
0566
0567
0568
0569
0570 rtems_status_code rtems_regulator_send(
0571 rtems_regulator_instance *regulator,
0572 void *message,
0573 size_t length
0574 )
0575 {
0576 _Regulator_Control *the_regulator;
0577 rtems_status_code status;
0578 _Regulator_Message_t regulator_message;
0579
0580 the_regulator = (_Regulator_Control *) regulator;
0581
0582
0583
0584
0585
0586 if (message == NULL) {
0587 return RTEMS_INVALID_ADDRESS;
0588 }
0589
0590 if (length == 0) {
0591 return RTEMS_INVALID_NUMBER;
0592 }
0593
0594
0595
0596
0597 the_regulator = _Regulator_Get(regulator, &status);
0598 if (the_regulator == NULL) {
0599 return status;
0600 }
0601
0602
0603
0604
0605
0606
0607 regulator_message.buffer = message;
0608 regulator_message.length = length;
0609
0610
0611
0612
0613
0614 status = rtems_message_queue_send(
0615 the_regulator->queue_id,
0616 ®ulator_message,
0617 sizeof(_Regulator_Message_t)
0618 );
0619 if (status != RTEMS_SUCCESSFUL) {
0620 return status;
0621 }
0622
0623 return status;
0624 }
0625
0626
0627
0628
0629 rtems_status_code rtems_regulator_get_statistics(
0630 rtems_regulator_instance *regulator,
0631 rtems_regulator_statistics *statistics
0632 )
0633 {
0634 _Regulator_Control *the_regulator;
0635 rtems_status_code status;
0636
0637
0638
0639
0640
0641 if (statistics == NULL) {
0642 return RTEMS_INVALID_ADDRESS;
0643 }
0644
0645
0646
0647
0648 the_regulator = _Regulator_Get(regulator, &status);
0649 if (the_regulator == NULL) {
0650 return status;
0651 }
0652
0653
0654
0655
0656
0657 memset(statistics, 0, sizeof(rtems_regulator_statistics));
0658
0659
0660
0661
0662
0663 statistics->obtained = the_regulator->Statistics.obtained;
0664 statistics->released = the_regulator->Statistics.released;
0665 statistics->delivered = the_regulator->Statistics.delivered;
0666
0667
0668
0669
0670
0671
0672
0673
0674 (void) rtems_rate_monotonic_get_statistics(
0675 the_regulator->delivery_thread_period_id,
0676 &statistics->period_statistics
0677 );
0678
0679 return RTEMS_SUCCESSFUL;
0680 }