Coverage Report

Created: 2025-06-15 00:57

/src/cmp_tool/lib/rdcu_compress/rdcu_rmap.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * @file   rdcu_rmap.c
3
 * @author Armin Luntzer (armin.luntzer@univie.ac.at)
4
 * @date   2018
5
 *
6
 * @copyright GPLv2
7
 * This program is free software; you can redistribute it and/or modify it
8
 * under the terms and conditions of the GNU General Public License,
9
 * version 2, as published by the Free Software Foundation.
10
 *
11
 * This program is distributed in the hope it will be useful, but WITHOUT
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14
 * more details.
15
 *
16
 * @brief RMAP RDCU link interface
17
 * @see FPGA Requirement Specification PLATO-IWF-PL-RS-005 Issue 0.7
18
 *
19
 *
20
 * Ideally, we would use asynchronous operations here, with a transaction log
21
 * that is served by another thread. However, we cannot assume that such
22
 * features will be available, so we'll do this by maintaining a mirror of the
23
 * RDCU's registers and memory, where instead of actively blocking with get()
24
 * and set() RMAP calls, they operate on the local copy and the user issues
25
 * sync() calls.
26
 *
27
 * To monitor the synchronisation status, we maintaining a transaction log
28
 * tracking the submitted command set. Response packets could be processed
29
 * by interrupt (or thread), but in this variant, we process the return packets
30
 * when the user calls rdcu_ctrl_sync_status()
31
 *
32
 * This is probably the nicest solution when it comes to call overhead, but it
33
 * requires 8 MiB of memory for the SRAM mirror and the some for the registers.
34
 *
35
 * Note that for simplicity , we assume that there is a working heap allocator
36
 * available, please adapt all malloc/free calls to your needs, or ask us
37
 * to do that for you.
38
 *
39
 * @note in order to run this on the GR712RC eval board, we set the SRAM mirror
40
 *   image to the boards SDRAM in rdcu_ctrl_init() and just malloc() it for
41
 *   the PC (see rdcu_ctrl_init)
42
 *
43
 * @note The interface requires that you provide an RX and a TX function,
44
 *   see rdcu_ctrl_init for the call interface.
45
 *   The TX function shall to return 0 on success, everything else
46
 *   is considered an error in submission. The RX function shall return
47
 *   the size of the packet buffer and accept NULL as call argument, on
48
 *   which it shall return the buffer size required to store the next
49
 *   pending packet.
50
 *   You can use these functions to adapt the actual backend, i.e. use
51
 *   your particular SpW interface or just redirect RX/TX to files
52
 *   or via a network connection.
53
 *
54
 * @note We don't have to serve more than one RDCU at any given time, so we
55
 *   track addresses and paths internally in a single instance. This also
56
 *   makes the interface less cluttered. Besides, I'm lazy.
57
 *
58
 *
59
 * @warning when operational, we expect to have exclusive control of the SpW link
60
 *
61
 * TODO: RMAP command response evaluation
62
 */
63
64
65
#include <stdint.h>
66
#include <stdlib.h>
67
#include <string.h>
68
69
#include "../common/byteorder.h"
70
#include "../common/cmp_debug.h"
71
#include "rmap.h"
72
#include "rdcu_rmap.h"
73
74
0
#define RDCU_CONFIG_DEBUG 0
75
76
static uint8_t rdcu_addr;
77
static uint8_t icu_addr;
78
79
static uint8_t *dpath;  /* destination path (to the RDCU) */
80
static uint8_t *rpath;  /* return path (to the ICU) */
81
static uint8_t dpath_len;
82
static uint8_t rpath_len;
83
84
static uint8_t dst_key; /* destination command key */
85
86
87
88
89
 /* generic calls, functions must be provided to init() */
90
static int32_t (*rmap_tx)(const void *hdr,  uint32_t hdr_size,
91
        const uint8_t non_crc_bytes,
92
        const void *data, uint32_t data_size);
93
static uint32_t (*rmap_rx)(uint8_t *pkt);
94
95
static uint32_t data_mtu; /* maximum data transfer size per unit */
96
97
98
99
100
101
102
103
104
105
106
/* For now we maintain a simple transaction log that works like this:
107
 * we allow up to 128 transfers, simply because this is how many response
108
 * packets the GRSPW2 SpW descriptor table can hold at any one time without
109
 * blocking the link.
110
 *
111
 * Every time a new transfer is to be submitted, we grab the first free
112
 * slot we encounter in the "in_use" array and use the index as the transaction
113
 * identifier of the RMAP packet. (Yes, this is potentially slow, as we may have
114
 * to iterate over the whole array every time if we're very busy with
115
 * transmissions, so there is room for improvement.)
116
 *
117
 * Every time a slot is retrieved, the "pending" counter is incremented to
118
 * have a fast indicator of the synchronisation status, i.e. if "pending"
119
 * is not set, the synchronisation procedure is complete and the local data may
120
 * be read, or the remote data has been written and further commands may be
121
 * issued.
122
 *
123
 * The local (mirror) start address of the requested remote address is stored
124
 * into the same slot in the "local_addr" array, so we'll know where to put the
125
 * data if we issue an RMAP_read command. This may be omitted for write
126
 * commands.
127
 *
128
 * Every time a response packet is received, the data (if any) is written to the
129
 * local address, using the length specified by RMAP packet, so be careful where
130
 * you place your buffers or registers. On success, the "in_use" slot is cleared
131
 * and the pending counter is improved.
132
 *
133
 * XXX: careful, no locking is used on any of the log data, so this is
134
 * single-thread-use only!
135
 *
136
 */
137
/* #define TRANS_LOG_SIZE 64  /1* GRSPW2 TX descriptor limit *1/ */
138
0
#define TRANS_LOG_SIZE 64000  /* increased because there are no response packets during packet generation */
139
static struct {
140
141
  uint8_t  in_use[TRANS_LOG_SIZE];
142
  void    *local_addr[TRANS_LOG_SIZE];
143
144
  int pending;
145
} trans_log;
146
147
148
/**
149
 * @brief grab a slot in the transaction log
150
 *
151
 * @param local_addr the local memory address
152
 *
153
 * @returns -1 on no slots, >= 0 for the transaction id
154
 */
155
156
static int trans_log_grab_slot(void *local_addr)
157
0
{
158
0
  int i;
159
0
  int slot = -1;
160
161
0
  for (i = 0; i < TRANS_LOG_SIZE; i++) {
162
163
0
    if (trans_log.in_use[i])
164
0
      continue;
165
166
    /* got one */
167
0
    slot = i;
168
0
    trans_log.in_use[slot] = 1;
169
0
    trans_log.local_addr[slot] = local_addr;
170
0
    trans_log.pending++;
171
0
    break;
172
0
  }
173
174
0
  return slot;
175
0
}
176
177
178
/**
179
 * @brief release a slot in the transaction log
180
 *
181
 * @param slot the id of the slot
182
 *
183
 */
184
185
static void trans_log_release_slot(int slot)
186
0
{
187
188
0
  if (slot < 0)
189
0
    return;
190
191
0
  if (slot >= TRANS_LOG_SIZE)
192
0
    return;
193
194
0
  if (!trans_log.in_use[slot])
195
0
    return;
196
197
0
  trans_log.in_use[slot] = 0;
198
0
  trans_log.pending--;
199
0
}
200
201
202
/**
203
 * @brief get the local address for a slot
204
 *
205
 * @param slot the id of the slot
206
 *
207
 * @returns the address or NULL if not found/slot not in use
208
 */
209
210
static void *trans_log_get_addr(int slot)
211
0
{
212
0
  if (slot < 0)
213
0
    return NULL;
214
215
0
  if (slot >= TRANS_LOG_SIZE)
216
0
    return NULL;
217
218
0
  if (!trans_log.in_use[slot])
219
0
    return NULL;
220
221
0
  return trans_log.local_addr[slot];
222
0
}
223
224
/**
225
 * @brief n rmap command transaction
226
 *
227
 * @returns number of packets processed or < 0 on error
228
 */
229
230
static int rdcu_process_rx(void)
231
0
{
232
0
  uint32_t n;
233
0
  int cnt = 0;
234
235
0
  uint32_t *local_addr;
236
237
0
  uint8_t *spw_pckt;
238
239
0
  struct rmap_pkt *rp;
240
241
242
0
  if (!rmap_rx)
243
0
    return -1;
244
245
  /* process all pending responses */
246
0
  while ((n = rmap_rx(NULL))) {
247
    /* we received something, allocate enough space for the packet */
248
0
    spw_pckt = (uint8_t *) malloc(n);
249
0
    if (!spw_pckt) {
250
0
      debug_print("malloc() for packet failed!");
251
0
      return -1;
252
0
    }
253
254
    /* read the packet */
255
0
    n = rmap_rx(spw_pckt);
256
257
0
    if (!n) {
258
0
      debug_print("Unknown error in rmap_rx()");
259
0
      free(spw_pckt);
260
0
      return -1;
261
0
    }
262
263
0
    cnt++;
264
265
0
    if (RDCU_CONFIG_DEBUG)
266
0
      rmap_parse_pkt(spw_pckt);
267
268
    /* convert format */
269
0
    rp = rmap_pkt_from_buffer(spw_pckt, n);
270
0
    free(spw_pckt);
271
272
0
    if (!rp) {
273
0
      debug_print("Error converting to RMAP packet");
274
0
      continue;
275
0
    }
276
277
0
    local_addr = trans_log_get_addr(rp->tr_id);
278
279
0
    if (!local_addr) {
280
0
      debug_print("Warning: response packet received not in transaction log");
281
0
      rmap_erase_packet(rp);
282
0
      continue;
283
0
    }
284
285
0
    if (rp->data_len & 0x3) {
286
0
      debug_print("Error: response packet data size is not a multiple of 4, transaction dropped");
287
0
      trans_log_release_slot(rp->tr_id);
288
0
      rmap_erase_packet(rp);
289
0
      return -1;
290
0
    }
291
292
0
    if (rp->data_len) {
293
0
      uint8_t crc8;
294
295
      /* convert endianness in-place if needed */
296
0
#ifdef __LITTLE_ENDIAN
297
0
      {
298
0
        uint32_t i, tmp;
299
300
0
        for (i = 0; i < rp->data_len; i += sizeof(tmp)) {
301
0
          memcpy(&tmp, &rp->data[i], sizeof(tmp));
302
0
          be32_to_cpus(&tmp);
303
0
          memcpy(&rp->data[i], &tmp, sizeof(tmp));
304
0
        }
305
0
      }
306
0
#endif /* __LITTLE_ENDIAN */
307
308
0
      crc8 = rmap_crc8(rp->data, rp->data_len);
309
0
      if (crc8 != rp->data_crc) {
310
0
        debug_print("Error: data CRC8 mismatch, data invalid or packet truncated. Transaction dropped");
311
312
0
        trans_log_release_slot(rp->tr_id);
313
0
        rmap_erase_packet(rp);
314
0
        return -1;
315
0
      }
316
317
0
      memcpy(local_addr, rp->data, rp->data_len);
318
0
    }
319
320
321
0
    trans_log_release_slot(rp->tr_id);
322
0
    rmap_erase_packet(rp);
323
0
  }
324
325
0
  return cnt;
326
0
}
327
328
329
/**
330
 * @brief submit an rmap command transaction
331
 *
332
 * @param cmd the rmap command
333
 * @param cmd_size the size of the rmap command
334
 * @param data the payload (may be NULL)
335
 * @param data_size the size of the payload
336
 *
337
 * @returns 0 on success, otherwise error
338
 */
339
340
int rdcu_submit_tx(const uint8_t *cmd,  uint32_t cmd_size,
341
       const uint8_t *data, uint32_t data_size)
342
0
{
343
  /* try to process pending responses */
344
0
  rdcu_process_rx();
345
346
0
  if (!rmap_tx)
347
0
    return -1;
348
349
0
  if (RDCU_CONFIG_DEBUG)
350
0
    debug_print("Transmitting RMAP command");
351
352
0
  if (rmap_tx(cmd, cmd_size, dpath_len, data, data_size)) {
353
0
    debug_print("rmap_tx() returned error!");
354
0
    return -1;
355
0
  }
356
357
0
  return 0;
358
0
}
359
360
361
/**
362
 * @brief generate an rmap command packet
363
 *
364
 * @param trans_id a transaction identifier
365
 *
366
 * @param cmd the command buffer; if NULL, the function returns the needed size
367
 *
368
 * @param rmap_cmd_type the rmap command type of the packet
369
 *
370
 * @param addr the address to read from or write to
371
 *
372
 * @param size the number of bytes to read or write
373
 *
374
 * @returns the size of the command data buffer or 0 on error
375
 */
376
377
int rdcu_gen_cmd(uint16_t trans_id, uint8_t *cmd,
378
     uint8_t rmap_cmd_type,
379
     uint32_t addr, uint32_t size)
380
0
{
381
0
  int n;
382
383
0
  struct rmap_pkt *pkt;
384
385
0
  pkt = rmap_create_packet();
386
0
  if (!pkt) {
387
0
    debug_print("Error creating packet");
388
0
    return 0;
389
0
  }
390
391
0
  rmap_set_dst(pkt, rdcu_addr);
392
0
  rmap_set_src(pkt, icu_addr);
393
0
  rmap_set_dest_path(pkt, dpath, dpath_len);
394
0
  rmap_set_reply_path(pkt, rpath, rpath_len);
395
0
  rmap_set_key(pkt, dst_key);
396
0
  rmap_set_cmd(pkt, rmap_cmd_type);
397
0
  rmap_set_tr_id(pkt, trans_id);
398
0
  rmap_set_data_addr(pkt, addr);
399
0
  rmap_set_data_len(pkt, size);
400
401
  /* determine header size */
402
0
  n = rmap_build_hdr(pkt, NULL);
403
404
0
  if (!cmd || n <= 0) {
405
0
    rmap_erase_packet(pkt);
406
0
    return n;
407
0
  }
408
409
0
  memset(cmd, 0, (size_t)n);  /* clear command buffer */
410
411
0
  n = rmap_build_hdr(pkt, cmd);
412
413
0
  rmap_erase_packet(pkt);
414
415
0
  return n;
416
0
}
417
418
419
420
421
422
/**
423
 * @brief submit a sync command
424
 *
425
 * @param fn the RDCU command generation function
426
 * @param addr the local address of the corresponding remote address
427
 * @param data_len the length of the data payload (0 for read commands)
428
 *
429
 * @note data_len must be a multiple of 4
430
 * @note all data is treated (and byte swapped) as 32 bit words
431
 *
432
 * @return 0 on success, otherwise error
433
 */
434
435
436
int rdcu_sync(int (*fn)(uint16_t trans_id, uint8_t *cmd),
437
        void *addr, uint32_t data_len)
438
0
{
439
0
  int n;
440
0
  int slot;
441
442
0
  uint8_t *rmap_cmd;
443
444
445
0
  if (data_len & 0x3)
446
0
    return -1;
447
448
0
  slot = trans_log_grab_slot(addr);
449
0
  if (slot < 0 || slot > UINT16_MAX)
450
0
    return -1;
451
452
453
  /* determine size of command */
454
0
  n = fn((uint16_t)slot, NULL);
455
0
  if (n <= 0) {
456
0
    debug_print("Error creating command packet");
457
0
    return -1;
458
0
  }
459
460
0
  rmap_cmd = (uint8_t *)malloc((size_t)n);
461
0
  if (!rmap_cmd) {
462
0
    debug_print("Error allocating rmap cmd");
463
0
    return -1;
464
0
  }
465
466
  /* now fill actual command */
467
0
  n = fn((uint16_t)slot, rmap_cmd);
468
0
  if (n <= 0) {
469
0
    debug_print("Error creating command packet");
470
0
    free(rmap_cmd);
471
0
    return -1;
472
0
  }
473
474
  /* convert endianness if needed */
475
0
#ifdef __LITTLE_ENDIAN
476
0
  if (data_len) {
477
0
    uint32_t i;
478
0
    uint32_t *tmp_buf = alloca(data_len);
479
0
    uint32_t *p = (uint32_t *)addr;
480
481
0
    for (i = 0; i < (data_len / 4); i++)
482
0
      tmp_buf[i] = cpu_to_be32(p[i]);
483
484
0
    addr = tmp_buf;
485
0
  }
486
0
#endif /* __LITTLE_ENDIAN */
487
488
0
  n = rdcu_submit_tx(rmap_cmd, (uint32_t)n, addr, data_len);
489
0
  free(rmap_cmd);
490
491
0
  return n;
492
0
}
493
494
495
496
/**
497
 * @brief submit a data sync command
498
 *
499
 * @param fn an RDCU data transfer generation function
500
 * @param addr the remote address
501
 * @param data the local data address
502
 * @param data_len the length of the data payload
503
 * @param read 0: write, otherwise read
504
 *
505
 * @return 0 on success, < 0: error, > 0: retry
506
 *
507
 * @note this one is a little redundant, but otherwise we'd have a lot of
508
 *   unused parameters on most of the control functions
509
 *
510
 * XXX need a parameter for read...meh...must think of something else
511
 */
512
513
514
int rdcu_sync_data(int (*fn)(uint16_t trans_id, uint8_t *cmd,
515
           uint32_t addr, uint32_t data_len),
516
       uint32_t addr, void *data, uint32_t data_len, int read)
517
0
{
518
0
  int n;
519
0
  int slot;
520
521
0
  uint8_t *rmap_cmd;
522
523
0
  rdcu_process_rx();
524
525
0
  slot = trans_log_grab_slot(data);
526
0
  if (slot < 0 || slot > UINT16_MAX) {
527
0
    if (RDCU_CONFIG_DEBUG)
528
0
      debug_print("Error: all slots busy!");
529
0
    return 1;
530
0
  }
531
532
533
  /* determine size of command */
534
0
  n = fn((uint16_t)slot, NULL, addr, data_len);
535
0
  if (n <= 0) {
536
0
    debug_print("Error creating command packet");
537
0
    return -1;
538
0
  }
539
540
541
0
  rmap_cmd = (uint8_t *)malloc((size_t)n);
542
0
  if (!rmap_cmd) {
543
0
    debug_print("Error allocating rmap cmd");
544
0
    return -1;
545
0
  }
546
547
  /* now fill actual command */
548
0
  n = fn((uint16_t)slot, rmap_cmd, addr, data_len);
549
0
  if (n <= 0) {
550
0
    debug_print("Error creating command packet");
551
0
    free(rmap_cmd);
552
0
    return -1;
553
0
  }
554
555
0
  if (read)
556
0
    n = rdcu_submit_tx(rmap_cmd, (uint32_t)n, NULL, 0);
557
0
  else
558
0
    n = rdcu_submit_tx(rmap_cmd, (uint32_t)n, data, data_len);
559
560
0
  free(rmap_cmd);
561
562
0
  return n;
563
0
}
564
565
566
567
/**
568
 * @brief create a complete package from header and payload data including CRC8
569
 *
570
 * @note this is a helper function to generate complete binary RMAP packet dumps
571
 *
572
 * @param blob the blob buffer; if NULL, the function returns the needed size
573
 *
574
 * @param[in]  cmd an rmap command buffer
575
 * @param[in]  cmd_size the size of the rmap command buffer
576
 * @param[in]  non_crc_bytes leading bytes in the header not path of the CRC
577
 * @param[in]  data a data buffer (may be NULL)
578
 * @param[in]  data_size the size of the data buffer (ignored if data is NULL)
579
 *
580
 * @note data_size must be a multiple of 4
581
 * @note this function will convert all data to big endian as 32 bit words
582
 *
583
 * @returns the size of the blob or 0 on error
584
 */
585
586
uint32_t rdcu_package(uint8_t *blob,
587
          const uint8_t *cmd, uint32_t cmd_size,
588
          const uint8_t non_crc_bytes,
589
          const uint8_t *data, uint32_t data_size)
590
0
{
591
0
  uint32_t n;
592
0
  int has_data_crc = 0;
593
0
  const struct rmap_instruction *ri;
594
595
596
0
  if (data_size & 0x3) /* must be multiple of 4 */
597
0
    return 0;
598
599
0
  if (!data_size)
600
0
    data = NULL;
601
602
0
  if (!cmd_size) {
603
0
    blob = NULL;
604
0
    return 0;
605
0
  }
606
607
608
  /* allocate space for header, header crc, data, data crc */
609
0
  n = cmd_size + 1;
610
611
0
  ri = (const struct rmap_instruction *)&cmd[non_crc_bytes + RMAP_INSTRUCTION];
612
613
  /* see if the type of command needs a data crc field at the end */
614
0
  switch (ri->cmd) {
615
0
  case RMAP_READ_MODIFY_WRITE_ADDR_INC:
616
0
  case RMAP_WRITE_ADDR_SINGLE:
617
0
  case RMAP_WRITE_ADDR_INC:
618
0
  case RMAP_WRITE_ADDR_SINGLE_VERIFY:
619
0
  case RMAP_WRITE_ADDR_INC_VERIFY:
620
0
  case RMAP_WRITE_ADDR_SINGLE_VERIFY_REPLY:
621
0
  case RMAP_WRITE_ADDR_INC_VERIFY_REPLY:
622
0
  case RMAP_WRITE_ADDR_INC_REPLY:
623
0
    has_data_crc = 1;
624
0
    n += 1;
625
0
    break;
626
0
  default:
627
0
    break;
628
0
  }
629
630
0
  if (data)
631
0
    n += data_size;
632
633
0
  if (!blob)
634
0
    return n;
635
636
0
  memcpy(&blob[0], cmd, cmd_size);
637
638
0
  blob[cmd_size] = rmap_crc8(&cmd[non_crc_bytes],
639
0
           cmd_size - non_crc_bytes);
640
641
0
  if (data) {
642
0
    memcpy(&blob[cmd_size + 1], data, data_size);
643
0
    blob[cmd_size + 1 + data_size] = rmap_crc8(&blob[cmd_size + 1], data_size);
644
0
  } else {
645
    /* if no data is present, data crc is 0x0 */
646
0
    if (has_data_crc)
647
0
      blob[cmd_size + 1] = 0x0;
648
0
  }
649
650
0
  return n;
651
0
}
652
653
654
/**
655
 * @brief sets the logical address of the RDCU
656
 * @param addr the address
657
 */
658
659
void rdcu_set_destination_logical_address(uint8_t addr)
660
0
{
661
0
  rdcu_addr = addr;
662
0
}
663
664
/**
665
 * @brief sets the logical address of the ICU
666
 * @param addr the address
667
 */
668
669
void rdcu_set_source_logical_address(uint8_t addr)
670
0
{
671
0
  icu_addr = addr;
672
0
}
673
674
675
/**
676
 * @brief set the destination path to the RDCU
677
 * @param path a byte array containing the path (may be NULL)
678
 * @param len the number of elements in the array
679
 *
680
 * @returns 0 on success, otherwise error
681
 *
682
 * @note the path array is taken as a reference, make sure to keep it around
683
 *   the maximum length of the path is 15 elements
684
 *   setting either path NULL or len 0 disables destination path addressing
685
 */
686
687
int rdcu_set_destination_path(uint8_t *path, uint8_t len)
688
0
{
689
0
  if (len > RMAP_MAX_PATH_LEN)
690
0
    return -1;
691
692
0
  if (!path || !len) {
693
0
    dpath     = NULL;
694
0
    dpath_len = 0;
695
0
    return 0;
696
0
  }
697
698
0
  dpath     = path;
699
0
  dpath_len = len;
700
701
0
  return 0;
702
0
}
703
704
705
/**
706
 * @brief set the return path to the ICU
707
 * @param path a byte array containing the path (may be NULL)
708
 * @param len the number of elements in the array
709
 *
710
 * @returns 0 on success, otherwise error
711
 *
712
 * @note the path array is taken as a reference, make sure to keep it around
713
 *   the maximum length of the path is 12 elements
714
 *   the number of elements must be a multiple of 4 (due to RMAP protocol)
715
 *   setting either path NULL or len 0 disables return path addressing
716
 */
717
718
int rdcu_set_return_path(uint8_t *path, uint8_t len)
719
0
{
720
0
  if (len > RMAP_MAX_REPLY_PATH_LEN)
721
0
    return -1;
722
723
0
  if (len & 0x3)
724
0
    return -1; /* not a multiple of 4 */
725
726
0
  if (!path || !len) {
727
0
    rpath     = NULL;
728
0
    rpath_len = 0;
729
0
    return 0;
730
0
  }
731
732
0
  rpath     = path;
733
0
  rpath_len = len;
734
735
0
  return 0;
736
0
}
737
738
739
/**
740
 * @brief set the destination command key to use
741
 *
742
 * @param key the destination key
743
 */
744
745
void rdcu_set_destination_key(uint8_t key)
746
0
{
747
0
  dst_key = key;
748
0
}
749
750
751
/**
752
 * @brief get the configured data MTU
753
 *
754
 * @returns the mtu
755
 */
756
757
uint32_t rdcu_get_data_mtu(void)
758
0
{
759
0
  return data_mtu;
760
0
}
761
762
763
/**
764
 * @brief get the RDCU <-> ICU mirror RMAP synchronisation status
765
 *
766
 * @returns 0: synchronised, > 0: operations pending
767
 */
768
769
int rdcu_rmap_sync_status(void)
770
0
{
771
  /* try to process pending responses */
772
0
  rdcu_process_rx();
773
774
0
  return trans_log.pending;
775
0
}
776
777
778
/**
779
 * @brief reset all entries in the RMAP transaction log
780
 */
781
782
void rdcu_rmap_reset_log(void)
783
0
{
784
0
  memset(trans_log.in_use, 0, sizeof(trans_log.in_use));  /* clear in_use buffer */
785
0
  trans_log.pending = 0;
786
0
}
787
788
789
/**
790
 * @brief initialise the rdcu control library
791
 *
792
 * @param mtu the maximum data transfer size per unit
793
 *
794
 * @param tx a function pointer to transmit an rmap command
795
 * @param rx function pointer to receive an rmap command
796
 *
797
 * @note tx is expected to return 0 on success
798
 *   rmap_rx is expected to return the number of packet bytes
799
 *
800
 * @returns 0 on success, otherwise error
801
 */
802
803
int rdcu_rmap_init(uint32_t mtu,
804
       int32_t (*tx)(const void *hdr,  uint32_t hdr_size,
805
         const uint8_t non_crc_bytes,
806
         const void *data, uint32_t data_size),
807
       uint32_t (*rx)(uint8_t *pkt))
808
0
{
809
0
  if (!tx)
810
0
    return -1;
811
812
0
  if (!rx)
813
0
    return -1;
814
815
0
  rmap_tx = tx;
816
0
  rmap_rx = rx;
817
818
0
  data_mtu = mtu;
819
820
0
  return 0;
821
0
}