aboutsummaryrefslogtreecommitdiff
path: root/ks_flash.c
blob: 10df54b3827d3a442db222bd66068832cf771825 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
/*
 * ks_flash.c
 * ----------
 * Keystore implementation in flash memory.
 *
 * Authors: Rob Austein, Fredrik Thulin
 * Copyright (c) 2015-2016, NORDUnet A/S All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * - Neither the name of the NORDUnet nor the names of its contributors may
 *   be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stddef.h>
#include <string.h>
#include <assert.h>

#include "hal.h"
#include "hal_internal.h"

#include "last_gasp_pin_internal.h"

#define HAL_OK CMIS_HAL_OK
#include "stm-keystore.h"
#undef HAL_OK

/*
 * Known block states.
 *
 * C does not guarantee any particular representation for enums, so
 * including enums directly in the block header isn't safe.  Instead,
 * we use an access method which casts when reading from the header.
 * Writing to the header isn't a problem, because C does guarantee
 * that enum is compatible with *some* integer type, it just doesn't
 * specify which one.
 */

typedef enum {
  BLOCK_TYPE_ERASED  = 0xFF, /* Pristine erased block (candidate for reuse) */
  BLOCK_TYPE_ZEROED  = 0x00, /* Zeroed block (recently used) */
  BLOCK_TYPE_KEY     = 0x55, /* Block contains key material */
  BLOCK_TYPE_ATTR    = 0x66, /* Block contains key attributes (overflow from key block) */
  BLOCK_TYPE_PIN     = 0xAA, /* Block contains PINs */
  BLOCK_TYPE_UNKNOWN = -1,   /* Internal code for "I have no clue what this is" */
} flash_block_type_t;

/*
 * Block status.
 */

typedef enum {
  BLOCK_STATUS_LIVE      = 0x66, /* This is a live flash block */
  BLOCK_STATUS_TOMBSTONE = 0x44, /* This is a tombstone left behind during an update  */
  BLOCK_STATUS_UNKNOWN   = -1,   /* Internal code for "I have no clue what this is" */
} flash_block_status_t;

/*
 * Common header for all flash block types.
 * A few of these fields are deliberately omitted from the CRC.
 */

typedef struct {
  uint8_t               block_type;
  uint8_t               block_status;
  uint8_t               total_chunks;
  uint8_t               this_chunk;
  hal_crc32_t           crc;
} flash_block_header_t;

/*
 * Key block.  Tail end of "der" field (after der_len) used for attributes.
 */

typedef struct {
  flash_block_header_t  header;
  hal_uuid_t            name;
  hal_key_type_t        type;
  hal_curve_name_t      curve;
  hal_key_flags_t       flags;
  size_t                der_len;
  unsigned              attributes_len;
  uint8_t               der[];  /* Must be last field -- C99 "flexible array member" */
} flash_key_block_t;

#define SIZEOF_FLASH_KEY_BLOCK_DER \
  (KEYSTORE_SUBSECTOR_SIZE - offsetof(flash_key_block_t, der))

/*
 * Key attribute overflow block (attributes which don't fit in der field of key block).
 */

typedef struct {
  flash_block_header_t  header;
  hal_uuid_t            name;
  unsigned              attributes_len;
  uint8_t               attributes[]; /* Must be last field -- C99 "flexible array member" */
} flash_attributes_block_t;

#define SIZEOF_FLASH_ATTRIBUTE_BLOCK_ATTRIBUTES \
  (KEYSTORE_SUBSECTOR_SIZE - offsetof(flash_attributes_block_t, attributes))

/*
 * PIN block.  Also includes space for backing up the KEK when
 * HAL_MKM_FLASH_BACKUP_KLUDGE is enabled.
 */

typedef struct {
  flash_block_header_t  header;
  hal_ks_pin_t          wheel_pin;
  hal_ks_pin_t          so_pin;
  hal_ks_pin_t          user_pin;
#if HAL_MKM_FLASH_BACKUP_KLUDGE
  uint32_t              kek_set;
  uint8_t               kek[KEK_LENGTH];
#endif
} flash_pin_block_t;

#define FLASH_KEK_SET   0x33333333

/*
 * One flash block.
 */

typedef union {
  uint8_t                       bytes[KEYSTORE_SUBSECTOR_SIZE];
  flash_block_header_t          header;
  flash_key_block_t             key;
  flash_attributes_block_t      attr;
  flash_pin_block_t             pin;
} flash_block_t;

/*
 * In-memory cache.
 */

typedef struct {
  unsigned            blockno;
  uint32_t            lru;
  flash_block_t       block;
} cache_block_t;

/*
 * In-memory database.
 *
 * The top-level structure is a static variable; the arrays are allocated at runtime
 * using hal_allocate_static_memory() because they can get kind of large.
 */

#ifndef KS_FLASH_CACHE_SIZE
#define KS_FLASH_CACHE_SIZE 4
#endif

#define NUM_FLASH_BLOCKS        KEYSTORE_NUM_SUBSECTORS

typedef struct {
  hal_ks_t              ks;                  /* Must be first (C "subclassing") */
  hal_ks_index_t        ksi;
  hal_ks_pin_t          wheel_pin;
  hal_ks_pin_t          so_pin;
  hal_ks_pin_t          user_pin;
  uint32_t              cache_lru;
  cache_block_t         *cache;
} db_t;

/*
 * PIN block gets the all-zeros UUID, which will never be returned by
 * the UUID generation code (by definition -- it's not a version 4 UUID).
 */

const static hal_uuid_t pin_uuid = {{0}};

/*
 * The in-memory database structure itself is small, but the arrays it
 * points to are large enough that they come from SDRAM allocated at
 * startup.
 */

static db_t db;

/*
 * Type safe casts.
 */

static inline flash_block_type_t block_get_type(const flash_block_t * const block)
{
  assert(block != NULL);
  return (flash_block_type_t) block->header.block_type;
}

static inline flash_block_status_t block_get_status(const flash_block_t * const block)
{
  assert(block != NULL);
  return (flash_block_status_t) block->header.block_status;
}

/*
 * Pick unused or least-recently-used slot in our in-memory cache.
 *
 * Updating lru values is caller's problem: if caller is using a cache
 * slot as a temporary buffer and there's no point in caching the
 * result, leave the lru values alone and the right thing will happen.
 */

static inline flash_block_t *cache_pick_lru(void)
{
  uint32_t best_delta = 0;
  int      best_index = 0;

  for (int i = 0; i < KS_FLASH_CACHE_SIZE; i++) {

    if (db.cache[i].blockno == ~0)
      return &db.cache[i].block;

    const uint32_t delta = db.cache_lru - db.cache[i].lru;
    if (delta > best_delta) {
      best_delta = delta;
      best_index = i;
    }

  }

  db.cache[best_index].blockno = ~0;
  return &db.cache[best_index].block;
}

/*
 * Find a block in our in-memory cache; return block or NULL if not present.
 */

static inline flash_block_t *cache_find_block(const unsigned blockno)
{
  for (int i = 0; i < KS_FLASH_CACHE_SIZE; i++)
    if (db.cache[i].blockno == blockno)
      return &db.cache[i].block;
  return NULL;
}

/*
 * Mark a block in our in-memory cache as being in current use.
 */

static inline void cache_mark_used(const flash_block_t * const block, const unsigned blockno)
{
  for (int i = 0; i < KS_FLASH_CACHE_SIZE; i++) {
    if (&db.cache[i].block == block) {
      db.cache[i].blockno = blockno;
      db.cache[i].lru = ++db.cache_lru;
      return;
    }
  }
}

/*
 * Release a block from the in-memory cache.
 */

static inline void cache_release(const flash_block_t * const block)
{
  if (block != NULL)
    cache_mark_used(block, ~0);
}

/*
 * Generate CRC-32 for a block.
 *
 * This function needs to understand the structure of
 * flash_block_header_t, so that it can skip over fields that
 * shouldn't be included in the CRC.
 */

static hal_crc32_t calculate_block_crc(const flash_block_t * const block)
{
  assert(block != NULL);

  hal_crc32_t crc = hal_crc32_init();

  crc = hal_crc32_update(crc, &block->header.block_type,
                         sizeof(block->header.block_type));

  crc = hal_crc32_update(crc, &block->header.total_chunks,
                         sizeof(block->header.total_chunks));

  crc = hal_crc32_update(crc, &block->header.this_chunk,
                         sizeof(block->header.this_chunk));

  crc = hal_crc32_update(crc, block->bytes + sizeof(flash_block_header_t),
                         sizeof(*block) - sizeof(flash_block_header_t));

  return hal_crc32_finalize(crc);
}

/*
 * Calculate block offset.
 */

static uint32_t block_offset(const unsigned blockno)
{
  return blockno * KEYSTORE_SUBSECTOR_SIZE;
}

/*
 * Read a flash block.
 *
 * Flash read on the Alpha is slow enough that it pays to check the
 * first page before reading the rest of the block.
 */

static hal_error_t block_read(const unsigned blockno, flash_block_t *block)
{
  if (block == NULL || blockno >= NUM_FLASH_BLOCKS || sizeof(*block) != KEYSTORE_SUBSECTOR_SIZE)
    return HAL_ERROR_IMPOSSIBLE;

  /* Sigh, magic numeric return codes */
  if (keystore_read_data(block_offset(blockno),
                         block->bytes,
                         KEYSTORE_PAGE_SIZE) != 1)
    return HAL_ERROR_KEYSTORE_ACCESS;

  switch (block_get_type(block)) {
  case BLOCK_TYPE_ERASED:
  case BLOCK_TYPE_ZEROED:
    return HAL_OK;
  case BLOCK_TYPE_KEY:
  case BLOCK_TYPE_PIN:
  case BLOCK_TYPE_ATTR:
    break;
  default:
    return HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE;
  }

  switch (block_get_status(block)) {
  case BLOCK_STATUS_LIVE:
  case BLOCK_STATUS_TOMBSTONE:
    break;
  default:
    return HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE;
  }

  /* Sigh, magic numeric return codes */
  if (keystore_read_data(block_offset(blockno) + KEYSTORE_PAGE_SIZE,
                         block->bytes + KEYSTORE_PAGE_SIZE,
                         sizeof(*block) - KEYSTORE_PAGE_SIZE) != 1)
    return HAL_ERROR_KEYSTORE_ACCESS;

  if (calculate_block_crc(block) != block->header.crc)
    return HAL_ERROR_KEYSTORE_BAD_CRC;

  return HAL_OK;
}

/*
 * Read a block using the cache.  Marking the block as used is left
 * for the caller, so we can avoid blowing out the cache when we
 * perform a ks_list() operation.
 */

static hal_error_t block_read_cached(const unsigned blockno, flash_block_t **block)
{
  if (block == NULL)
    return HAL_ERROR_IMPOSSIBLE;

  if ((*block = cache_find_block(blockno)) != NULL)
    return HAL_OK;

  if ((*block = cache_pick_lru()) == NULL)
    return HAL_ERROR_IMPOSSIBLE;

  return block_read(blockno, *block);
}

/*
 * Convert a live block into a tombstone.  Caller is responsible for
 * making sure that the block being converted is valid; since we don't
 * need to update the CRC for this, we just modify the first page.
 */

static hal_error_t block_deprecate(const unsigned blockno)
{
  if (blockno >= NUM_FLASH_BLOCKS)
    return HAL_ERROR_IMPOSSIBLE;

  uint8_t page[KEYSTORE_PAGE_SIZE];
  flash_block_header_t *header = (void *) page;
  uint32_t offset = block_offset(blockno);

  /* Sigh, magic numeric return codes */
  if (keystore_read_data(offset, page, sizeof(page)) != 1)
    return HAL_ERROR_KEYSTORE_ACCESS;

  header->block_status = BLOCK_STATUS_TOMBSTONE;

  /* Sigh, magic numeric return codes */
  if (keystore_write_data(offset, page, sizeof(page)) != 1)
    return HAL_ERROR_KEYSTORE_ACCESS;

  return HAL_OK;
}

/*
 * Zero (not erase) a flash block.  Just need to zero the first page.
 */

static hal_error_t block_zero(const unsigned blockno)
{
  if (blockno >= NUM_FLASH_BLOCKS)
    return HAL_ERROR_IMPOSSIBLE;

  uint8_t page[KEYSTORE_PAGE_SIZE] = {0};

  /* Sigh, magic numeric return codes */
  if (keystore_write_data(block_offset(blockno), page, sizeof(page)) != 1)
    return HAL_ERROR_KEYSTORE_ACCESS;

  return HAL_OK;
}

/*
 * Erase a flash block.  Also see block_erase_maybe(), below.
 */

static hal_error_t block_erase(const unsigned blockno)
{
  if (blockno >= NUM_FLASH_BLOCKS)
    return HAL_ERROR_IMPOSSIBLE;

  /* Sigh, magic numeric return codes */
  if (keystore_erase_subsectors(blockno, blockno) != 1)
    return HAL_ERROR_KEYSTORE_ACCESS;

  return HAL_OK;
}

/*
 * Erase a flash block if it hasn't already been erased.
 * May not be necessary, trying to avoid unnecessary wear.
 *
 * Unclear whether there's any sane reason why this needs to be
 * constant time, given how slow erasure is.  But side channel attacks
 * can be tricky things, and it's theoretically possible that we could
 * leak information about, eg, key length, so we do constant time.
 */

static hal_error_t block_erase_maybe(const unsigned blockno)
{
  if (blockno >= NUM_FLASH_BLOCKS)
    return HAL_ERROR_IMPOSSIBLE;

  uint8_t mask = 0xFF;

  for (uint32_t a = block_offset(blockno); a < block_offset(blockno + 1); a += KEYSTORE_PAGE_SIZE) {
    uint8_t page[KEYSTORE_PAGE_SIZE];
    if (keystore_read_data(a, page, sizeof(page)) != 1)
      return HAL_ERROR_KEYSTORE_ACCESS;
    for (int i = 0; i < KEYSTORE_PAGE_SIZE; i++)
      mask &= page[i];
  }

  return mask == 0xFF ? HAL_OK : block_erase(blockno);
}

/*
 * Write a flash block, calculating CRC when appropriate.
 */

static hal_error_t block_write(const unsigned blockno, flash_block_t *block)
{
  if (block == NULL || blockno >= NUM_FLASH_BLOCKS || sizeof(*block) != KEYSTORE_SUBSECTOR_SIZE)
    return HAL_ERROR_IMPOSSIBLE;

  hal_error_t err = block_erase_maybe(blockno);

  if (err != HAL_OK)
    return err;

  switch (block_get_type(block)) {
  case BLOCK_TYPE_KEY:
  case BLOCK_TYPE_PIN:
  case BLOCK_TYPE_ATTR:
    block->header.crc = calculate_block_crc(block);
    break;
  default:
    break;
  }

  /* Sigh, magic numeric return codes */
  if (keystore_write_data(block_offset(blockno), block->bytes, sizeof(*block)) != 1)
    return HAL_ERROR_KEYSTORE_ACCESS;

  return HAL_OK;
}

/*
 * Update one flash block, including zombie jamboree.
 */

static hal_error_t block_update(const unsigned b1, flash_block_t *block,
                                const hal_uuid_t * const uuid, const unsigned chunk, int *hint)
{
  if (block == NULL)
    return HAL_ERROR_IMPOSSIBLE;

  if (db.ksi.used == db.ksi.size)
    return HAL_ERROR_NO_KEY_INDEX_SLOTS;

  cache_release(block);

  hal_error_t err;
  unsigned b2;

  if ((err = block_deprecate(b1))                                       != HAL_OK ||
      (err = hal_ks_index_replace(&db.ksi, uuid, chunk, &b2, hint))     != HAL_OK ||
      (err = block_write(b2, block))                                    != HAL_OK ||
      (err = block_zero(b1))                                            != HAL_OK)
    return err;

  cache_mark_used(block, b2);

  return block_erase_maybe(db.ksi.index[db.ksi.used]);
}

/*
 * Forward reference.
 */

static hal_error_t fetch_pin_block(unsigned *b, flash_block_t **block);

/*
 * Initialize keystore.  This includes various tricky bits, some of
 * which attempt to preserve the free list ordering across reboots, to
 * improve our simplistic attempt at wear leveling, others attempt to
 * recover from unclean shutdown.
 */

static inline void *gnaw(uint8_t **mem, size_t *len, const size_t size)
{
  if (mem == NULL || *mem == NULL || len == NULL || size > *len)
    return NULL;
  void *ret = *mem;
  *mem += size;
  *len -= size;
  return ret;
}

static hal_error_t ks_init(const hal_ks_driver_t * const driver)
{
  /*
   * Initialize the in-memory database.
   */

  size_t len = (sizeof(*db.ksi.index) * NUM_FLASH_BLOCKS +
                sizeof(*db.ksi.names) * NUM_FLASH_BLOCKS +
                sizeof(*db.cache)     * KS_FLASH_CACHE_SIZE);

  uint8_t *mem = hal_allocate_static_memory(len);

  if (mem == NULL)
    return HAL_ERROR_ALLOCATION_FAILURE;

  memset(&db, 0, sizeof(db));
  memset(mem, 0, len);

  db.ksi.index = gnaw(&mem, &len, sizeof(*db.ksi.index) * NUM_FLASH_BLOCKS);
  db.ksi.names = gnaw(&mem, &len, sizeof(*db.ksi.names) * NUM_FLASH_BLOCKS);
  db.cache     = gnaw(&mem, &len, sizeof(*db.cache)     * KS_FLASH_CACHE_SIZE);
  db.ksi.size  = NUM_FLASH_BLOCKS;
  db.ksi.used  = 0;

  if (db.ksi.index == NULL || db.ksi.names == NULL || db.cache == NULL)
    return HAL_ERROR_IMPOSSIBLE;

  for (int i = 0; i < KS_FLASH_CACHE_SIZE; i++)
    db.cache[i].blockno = ~0;

  /*
   * Scan existing content of flash to figure out what we've got.
   * This gets a bit involved due to the need to recover from things
   * like power failures at inconvenient times.
   */

  flash_block_type_t   block_types[NUM_FLASH_BLOCKS];
  flash_block_status_t block_status[NUM_FLASH_BLOCKS];
  flash_block_t *block = cache_pick_lru();
  int first_erased = -1;
  hal_error_t err;
  uint16_t n = 0;

  if (block == NULL)
    return HAL_ERROR_IMPOSSIBLE;

  for (int i = 0; i < NUM_FLASH_BLOCKS; i++) {

    /*
     * Read one block.  If the CRC is bad or the block type is
     * unknown, it's old data we don't understand, something we were
     * writing when we crashed, or bad flash; in any of these cases,
     * we want the block to ends up near the end of the free list.
     */

    err = block_read(i, block);

    if (err == HAL_ERROR_KEYSTORE_BAD_CRC || err == HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE)
      block_types[i] = BLOCK_TYPE_UNKNOWN;

    else if (err == HAL_OK)
      block_types[i] = block_get_type(block);

    else
      return err;

    switch (block_types[i]) {
    case BLOCK_TYPE_KEY:
    case BLOCK_TYPE_PIN:
    case BLOCK_TYPE_ATTR:
      block_status[i] = block_get_status(block);
      break;
    default:
      block_status[i] = BLOCK_STATUS_UNKNOWN;
    }

    /*
     * First erased block we see is head of the free list.
     */

    if (block_types[i] == BLOCK_TYPE_ERASED && first_erased < 0)
      first_erased = i;

    /*
     * If it's a valid data block, include it in the index.  We remove
     * tombstones (if any) below, for now it's easiest to include them
     * in the index, so we can look them up by name if we must.
     */

    const hal_uuid_t *uuid = NULL;

    switch (block_types[i]) {
    case BLOCK_TYPE_KEY:        uuid = &block->key.name;        break;
    case BLOCK_TYPE_ATTR:       uuid = &block->attr.name;       break;
    case BLOCK_TYPE_PIN:        uuid = &pin_uuid;               break;
    default:                    /* Keep GCC happy */            break;
    }

    if (uuid != NULL) {
      db.ksi.names[i].name = *uuid;
      db.ksi.names[i].chunk = block->header.this_chunk;
      db.ksi.index[n++] = i;
    }
  }

  db.ksi.used = n;

  assert(db.ksi.used <= db.ksi.size);

  /*
   * At this point we've built the (unsorted) index from all the valid
   * blocks.  Now we need to insert free and unrecognized blocks into
   * the free list in our preferred order.  It's possible that there's
   * a better way to do this than linear scan, but this is just
   * integer comparisons in a fairly small data set, so it's probably
   * not worth trying to optimize.
   */

  if (n < db.ksi.size)
    for (int i = 0; i < NUM_FLASH_BLOCKS; i++)
      if (block_types[i] == BLOCK_TYPE_ERASED)
        db.ksi.index[n++] = i;

  if (n < db.ksi.size)
    for (int i = first_erased; i < NUM_FLASH_BLOCKS; i++)
      if (block_types[i] == BLOCK_TYPE_ZEROED)
        db.ksi.index[n++] = i;

  if (n < db.ksi.size)
    for (int i = 0; i < first_erased; i++)
      if (block_types[i] == BLOCK_TYPE_ZEROED)
        db.ksi.index[n++] = i;

  if (n < db.ksi.size)
    for (int i = 0; i < NUM_FLASH_BLOCKS; i++)
      if (block_types[i] == BLOCK_TYPE_UNKNOWN)
        db.ksi.index[n++] = i;

  assert(n == db.ksi.size);

  /*
   * Initialize the index.
   */

  if ((err = hal_ks_index_setup(&db.ksi)) != HAL_OK)
    return err;

  /*
   * Deal with tombstones.  These are blocks left behind when
   * something bad (like a power failure) happened while we updating.
   * The sequence of operations while updating is designed so that,
   * barring a bug or a hardware failure, we should never lose data.
   *
   * For any tombstone we find, we start by looking for all the blocks
   * with a matching UUID, then see what valid sequences we can
   * construct from what we found.
   *
   * If we can construct a valid sequence of live blocks, the complete
   * update was written out, and we just need to zero the tombstones.
   *
   * Otherwise, if we can construct a complete sequence of tombstone
   * blocks, the update failed before it was completely written, so we
   * have to zero the incomplete sequence of live blocks then restore
   * from the tombstones.
   *
   * Otherwise, if the live and tombstone blocks taken together form a
   * valid sequence, the update failed while deprecating the old live
   * blocks, and the update itself was not written, so we need to
   * restore the tombstones and leave the live blocks alone.
   *
   * If none of the above applies, we don't understand what happened,
   * which is a symptom of either a bug or a hardware failure more
   * serious than simple loss of power or reboot at an inconvenient
   * time, so we error out to avoid accidental loss of data.
   */

  for (int i = 0; i < NUM_FLASH_BLOCKS; i++) {

    if (block_status[i] != BLOCK_STATUS_TOMBSTONE)
      continue;

    hal_uuid_t name = db.ksi.names[i].name;
    unsigned n_blocks;
    int where = -1;

    if ((err = hal_ks_index_find_range(&db.ksi, &name, 0, &n_blocks, NULL, &where)) != HAL_OK)
      return err;

    while (where > 0 && !hal_uuid_cmp(&name, &db.ksi.names[db.ksi.index[where - 1]].name)) {
      where--;
      n_blocks++;
    }

    int live_ok = 1, tomb_ok = 1, join_ok = 1;
    unsigned n_live = 0, n_tomb = 0;
    unsigned i_live = 0, i_tomb = 0;

    for (int j = 0; j < n_blocks; j++) {
      unsigned b = db.ksi.index[where + j];
      switch (block_status[b]) {
      case BLOCK_STATUS_LIVE:           n_live++;       break;
      case BLOCK_STATUS_TOMBSTONE:      n_tomb++;       break;
      default:                          return HAL_ERROR_IMPOSSIBLE;
      }
    }

    uint16_t live_blocks[n_live], tomb_blocks[n_tomb];

    for (int j = 0; j < n_blocks; j++) {
      unsigned b = db.ksi.index[where + j];

      if ((err = block_read(b, block)) != HAL_OK)
        return err;

      join_ok &= block->header.this_chunk == j && block->header.total_chunks == n_blocks;

      switch (block_status[b]) {
      case BLOCK_STATUS_LIVE:
        live_blocks[i_live] = b;
        live_ok &= block->header.this_chunk == i_live++ && block->header.total_chunks == n_live;
        break;
      case BLOCK_STATUS_TOMBSTONE:
        tomb_blocks[i_tomb] = b;
        tomb_ok &= block->header.this_chunk == i_tomb++ && block->header.total_chunks == n_tomb;
        break;
      default:
        return HAL_ERROR_IMPOSSIBLE;
      }
    }

    if (!live_ok && !tomb_ok && !join_ok)
      return HAL_ERROR_KEYSTORE_LOST_DATA;

    if (live_ok) {
      for (int j = 0; j < n_tomb; j++) {
        const unsigned b = tomb_blocks[j];
        if ((err = block_zero(b)) != HAL_OK)
          return err;
        block_types[b]  = BLOCK_TYPE_ZEROED;
        block_status[b] = BLOCK_STATUS_UNKNOWN;
      }
    }

    else if (tomb_ok) {
      for (int j = 0; j < n_live; j++) {
        const unsigned b = live_blocks[j];
        if ((err = block_zero(b)) != HAL_OK)
          return err;
        block_types[b]  = BLOCK_TYPE_ZEROED;
        block_status[b] = BLOCK_STATUS_UNKNOWN;
      }
    }

    if (live_ok) {
      memcpy(&db.ksi.index[where], live_blocks, n_live * sizeof(*db.ksi.index));
      memmove(&db.ksi.index[where + n_live], &db.ksi.index[where + n_blocks],
              (db.ksi.size - where - n_blocks) * sizeof(*db.ksi.index));
      memcpy(&db.ksi.index[db.ksi.size - n_tomb], tomb_blocks, n_tomb * sizeof(*db.ksi.index));
      db.ksi.used -= n_tomb;
      n_blocks = n_live;
    }

    else if (tomb_ok) {
      memcpy(&db.ksi.index[where], tomb_blocks, n_tomb * sizeof(*db.ksi.index));
      memmove(&db.ksi.index[where + n_tomb], &db.ksi.index[where + n_blocks],
              (db.ksi.size - where - n_blocks) * sizeof(*db.ksi.index));
      memcpy(&db.ksi.index[db.ksi.size - n_live], live_blocks, n_live * sizeof(*db.ksi.index));
      db.ksi.used -= n_live;
      n_blocks = n_tomb;
    }

    for (int j = 0; j < n_blocks; j++) {
      int hint = where + j;
      unsigned b1 = db.ksi.index[hint], b2;
      if (block_status[b1] != BLOCK_STATUS_TOMBSTONE)
        continue;
      if ((err = block_read(b1, block)) != HAL_OK)
        return err;
      block->header.block_status = BLOCK_STATUS_LIVE;
      if ((err = hal_ks_index_replace(&db.ksi, &name, j, &b2, &hint)) != HAL_OK ||
          (err = block_write(b2, block)) != HAL_OK)
        return err;
      block_types[b1]  = BLOCK_TYPE_ZEROED;
      block_status[b1] = BLOCK_STATUS_UNKNOWN;
      block_status[b2] = BLOCK_STATUS_LIVE;
    }
  }

  err = fetch_pin_block(NULL, &block);

  if (err == HAL_OK) {
    db.wheel_pin = block->pin.wheel_pin;
    db.so_pin    = block->pin.so_pin;
    db.user_pin  = block->pin.user_pin;
  }

  else if (err != HAL_ERROR_KEY_NOT_FOUND)
    return err;

  else {
    /*
     * We found no PIN block, so create one, with the user and so PINs
     * cleared and the wheel PIN set to the last-gasp value.  The
     * last-gasp WHEEL PIN is a terrible answer, but we need some kind
     * of bootstrapping mechanism when all else fails.  If you have a
     * better suggestion, we'd love to hear it.
     */

    unsigned b;

    memset(block, 0xFF, sizeof(*block));

    block->header.block_type   = BLOCK_TYPE_PIN;
    block->header.block_status = BLOCK_STATUS_LIVE;
    block->header.total_chunks = 1;
    block->header.this_chunk   = 0;

    block->pin.wheel_pin = db.wheel_pin = hal_last_gasp_pin;
    block->pin.so_pin    = db.so_pin;
    block->pin.user_pin  = db.user_pin;

    if ((err = hal_ks_index_add(&db.ksi, &pin_uuid, 0, &b, NULL)) != HAL_OK)
      return err;

    cache_mark_used(block, b);

    err = block_write(b, block);

    cache_release(block);

    if (err != HAL_OK)
      return err;
  }

  /*
   * Erase first block on free list if it's not already erased.
   */

  if (db.ksi.used < db.ksi.size &&
      (err = block_erase_maybe(db.ksi.index[db.ksi.used])) != HAL_OK)
    return err;

  /*
   * And we're finally done.
   */

  db.ks.driver = driver;

  return HAL_OK;
}

static hal_error_t ks_shutdown(const hal_ks_driver_t * const driver)
{
  if (db.ks.driver != driver)
    return HAL_ERROR_KEYSTORE_ACCESS;
  return HAL_OK;
}

static hal_error_t ks_open(const hal_ks_driver_t * const driver,
                                    hal_ks_t **ks)
{
  if (driver != hal_ks_token_driver || ks == NULL)
    return HAL_ERROR_BAD_ARGUMENTS;

  *ks = &db.ks;
  return HAL_OK;
}

static hal_error_t ks_close(hal_ks_t *ks)
{
  if (ks != NULL && ks != &db.ks)
    return HAL_ERROR_BAD_ARGUMENTS;

  return HAL_OK;
}

static inline int acceptable_key_type(const hal_key_type_t type)
{
  switch (type) {
  case HAL_KEY_TYPE_RSA_PRIVATE:
  case HAL_KEY_TYPE_EC_PRIVATE:
  case HAL_KEY_TYPE_RSA_PUBLIC:
  case HAL_KEY_TYPE_EC_PUBLIC:
    return 1;
  default:
    return 0;
  }
}

static hal_error_t ks_store(hal_ks_t *ks,
                            hal_pkey_slot_t *slot,
                            const uint8_t * const der, const size_t der_len)
{
  if (ks != &db.ks || slot == NULL || der == NULL || der_len == 0 || !acceptable_key_type(slot->type))
    return HAL_ERROR_BAD_ARGUMENTS;

  flash_block_t *block = cache_pick_lru();
  flash_key_block_t *k = &block->key;
  uint8_t kek[KEK_LENGTH];
  size_t kek_len;
  hal_error_t err;
  unsigned b;

  if (block == NULL)
    return HAL_ERROR_IMPOSSIBLE;

  if ((err = hal_ks_index_add(&db.ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK)
    return err;

  cache_mark_used(block, b);

  memset(block, 0xFF, sizeof(*block));

  block->header.block_type   = BLOCK_TYPE_KEY;
  block->header.block_status = BLOCK_STATUS_LIVE;
  block->header.total_chunks = 1;
  block->header.this_chunk   = 0;

  k->name    = slot->name;
  k->type    = slot->type;
  k->curve   = slot->curve;
  k->flags   = slot->flags;
  k->der_len = SIZEOF_FLASH_KEY_BLOCK_DER;
  k->attributes_len = 0;

  if ((err = hal_mkm_get_kek(kek, &kek_len, sizeof(kek))) == HAL_OK)
    err = hal_aes_keywrap(NULL, kek, kek_len, der, der_len, k->der, &k->der_len);

  memset(kek, 0, sizeof(kek));

  if (err == HAL_OK &&
      (err = block_write(b, block)) == HAL_OK)
    return HAL_OK;

  memset(block, 0, sizeof(*block));
  cache_release(block);
  (void) hal_ks_index_delete(&db.ksi, &slot->name, 0, NULL, &slot->hint);
  return err;
}

static hal_error_t ks_fetch(hal_ks_t *ks,
                            hal_pkey_slot_t *slot,
                            uint8_t *der, size_t *der_len, const size_t der_max)
{
  if (ks != &db.ks || slot == NULL)
    return HAL_ERROR_BAD_ARGUMENTS;

  flash_block_t *block;
  hal_error_t err;
  unsigned b;

  if ((err = hal_ks_index_find(&db.ksi, &slot->name, 0, &b, &slot->hint)) != HAL_OK ||
      (err = block_read_cached(b, &block))                                != HAL_OK)
    return err;

  if (block_get_type(block) != BLOCK_TYPE_KEY)
    return HAL_ERROR_KEY_NOT_FOUND;

  cache_mark_used(block, b);

  flash_key_block_t *k = &block->key;

  slot->type  = k->type;
  slot->curve = k->curve;
  slot->flags = k->flags;

  if (der == NULL && der_len != NULL)
    *der_len = k->der_len;

  if (der != NULL) {

    uint8_t kek[KEK_LENGTH];
    size_t kek_len, der_len_;
    hal_error_t err;

    if (der_len == NULL)
      der_len = &der_len_;

    *der_len = der_max;

    if ((err = hal_mkm_get_kek(kek, &kek_len, sizeof(kek))) == HAL_OK)
      err = hal_aes_keyunwrap(NULL, kek, kek_len, k->der, k->der_len, der, der_len);

    memset(kek, 0, sizeof(kek));

    if (err != HAL_OK)
      return err;
  }

  return HAL_OK;
}

static hal_error_t ks_delete(hal_ks_t *ks,
                             hal_pkey_slot_t *slot)
{
  if (ks != &db.ks || slot == NULL)
    return HAL_ERROR_BAD_ARGUMENTS;

  hal_error_t err;
  unsigned n;

  if ((err = hal_ks_index_delete_range(&db.ksi, &slot->name, 0, &n, NULL, &slot->hint)) != HAL_OK)
    return err;

  unsigned b[n];

  if ((err = hal_ks_index_delete_range(&db.ksi, &slot->name, n, NULL, b, &slot->hint)) != HAL_OK)
    return err;

  for (int i = 0; i < n; i++) {
    cache_release(cache_find_block(b[i]));
    if ((err = block_zero(b[i])) != HAL_OK)
      return err;
  }

  return block_erase_maybe(db.ksi.index[db.ksi.used]);
}

static hal_error_t ks_list(hal_ks_t *ks,
                           const hal_client_handle_t client,
                           const hal_session_handle_t session,
                           hal_pkey_info_t *result,
                           unsigned *result_len,
                           const unsigned result_max)
{
  if (ks != &db.ks || result == NULL || result_len == NULL)
    return HAL_ERROR_BAD_ARGUMENTS;

  if (db.ksi.used > result_max)
    return HAL_ERROR_RESULT_TOO_LONG;

  flash_block_t *block;
  hal_error_t err;
  unsigned b;

  *result_len = 0;

  for (int i = 0; i < db.ksi.used; i++) {
    b = db.ksi.index[i];

    if ((err = block_read_cached(b, &block)) != HAL_OK)
      return err;

    if (block_get_type(block) != BLOCK_TYPE_KEY || block->header.this_chunk > 0)
      continue;

    result[*result_len].type  = block->key.type;
    result[*result_len].curve = block->key.curve;
    result[*result_len].flags = block->key.flags;
    result[*result_len].name  = block->key.name;
    ++ *result_len;
  }

  return HAL_OK;
}

static inline hal_error_t locate_attributes(flash_block_t *block, const unsigned chunk,
                                            uint8_t **bytes, size_t *bytes_len,
                                            unsigned **attrs_len)
{
  if (block == NULL || bytes == NULL || bytes_len == NULL || attrs_len == NULL)
    return HAL_ERROR_IMPOSSIBLE;

  if (chunk == 0) {
    if (block_get_type(block) != BLOCK_TYPE_KEY)
      return HAL_ERROR_KEY_NOT_FOUND;
    *attrs_len = &block->key.attributes_len;
    *bytes = block->key.der + block->key.der_len;
    *bytes_len = SIZEOF_FLASH_KEY_BLOCK_DER - block->key.der_len;
  }

  else {
    if (block_get_type(block) != BLOCK_TYPE_ATTR)
      return HAL_ERROR_KEY_NOT_FOUND;
    *attrs_len = &block->attr.attributes_len;
    *bytes = block->attr.attributes;
    *bytes_len = SIZEOF_FLASH_ATTRIBUTE_BLOCK_ATTRIBUTES;
  }

  return HAL_OK;
}

static hal_error_t ks_match(hal_ks_t *ks,
                            const hal_client_handle_t client,
                            const hal_session_handle_t session,
                            const hal_key_type_t type,
                            const hal_curve_name_t curve,
                            const hal_key_flags_t flags,
                            hal_rpc_pkey_attribute_t *attributes,
                            const unsigned attributes_len,
                            hal_uuid_t *result,
                            unsigned *result_len,
                            const unsigned result_max,
                            const hal_uuid_t * const previous_uuid)
{
  if (ks == NULL || attributes == NULL ||
      result == NULL || result_len == NULL || previous_uuid == NULL)
    return HAL_ERROR_BAD_ARGUMENTS;

  uint8_t need_attr[attributes_len > 0 ? attributes_len : 1];
  flash_block_t *block;
  int possible = 0;
  hal_error_t err;
  int i = -1;

  *result_len = 0;

  err = hal_ks_index_find(&db.ksi, previous_uuid, 0, NULL, &i);

  if (err == HAL_ERROR_KEY_NOT_FOUND)
    i--;
  else if (err != HAL_OK)
    return err;

  while (*result_len < result_max) {

    if (++i >= db.ksi.used)
      return HAL_OK;

    unsigned b = db.ksi.index[i];

    if (db.ksi.names[b].chunk == 0)
      possible = 1;

    if (!possible)
      continue;

    if ((err = block_read_cached(b, &block)) != HAL_OK)
      return err;

    if (db.ksi.names[b].chunk == 0) {
      memset(need_attr, 1, sizeof(need_attr));
      possible = ((type == HAL_KEY_TYPE_NONE || type  == block->key.type) &&
                  (curve == HAL_CURVE_NONE   || curve == block->key.curve));
    }

    if (!possible)
      continue;

    if (attributes_len > 0) {
      uint8_t *bytes = NULL;
      size_t bytes_len = 0;
      unsigned *attrs_len;

      if ((err = locate_attributes(block, db.ksi.names[b].chunk,
                                   &bytes, &bytes_len, &attrs_len)) != HAL_OK)
        return err;

      if (*attrs_len > 0) {
        hal_rpc_pkey_attribute_t attrs[*attrs_len];

        if ((err = hal_ks_attribute_scan(bytes, bytes_len, attrs, *attrs_len, NULL)) != HAL_OK)
          return err;

        for (int j = 0; possible && j < attributes_len; j++) {

          if (!need_attr[j])
            continue;

          for (hal_rpc_pkey_attribute_t *a = attrs; a < attrs + *attrs_len; a++) {
            if (a->type != attributes[j].type)
              continue;
            need_attr[j] = 0;
            possible = (a->length == attributes[j].length &&
                        !memcmp(a->value, attributes[j].value, a->length));
            break;
          }
        }
      }
    }

    if (!possible)
      continue;

    if (attributes_len > 0 && memchr(need_attr, 1, sizeof(need_attr)) != NULL)
      continue;

    result[*result_len] = db.ksi.names[b].name;
    ++*result_len;
    possible = 0;
  }

  return HAL_ERROR_RESULT_TOO_LONG;
}

static  hal_error_t ks_set_attribute(hal_ks_t *ks,
                                     hal_pkey_slot_t *slot,
                                     const uint32_t type,
                                     const uint8_t * const value,
                                     const size_t value_len)
{
  if (ks != &db.ks || slot == NULL)
    return HAL_ERROR_BAD_ARGUMENTS;

  /*
   * Try to add new attribute as a single-block update.
   */

  flash_block_t *block;
  unsigned chunk = 0;
  hal_error_t err;

  do {
    int hint = slot->hint + chunk;
    unsigned b;

    if ((err = hal_ks_index_find(&db.ksi, &slot->name, chunk, &b, &hint)) != HAL_OK ||
        (err = block_read_cached(b, &block))                              != HAL_OK)
      return err;

    if (block->header.this_chunk != chunk)
      return HAL_ERROR_IMPOSSIBLE;

    if (chunk == 0)
      slot->hint = hint;

    uint8_t *bytes = NULL;
    size_t bytes_len = 0;
    unsigned *attrs_len;

    if ((err = locate_attributes(block, chunk, &bytes, &bytes_len, &attrs_len)) != HAL_OK)
      return err;

    cache_mark_used(block, b);

    hal_rpc_pkey_attribute_t attrs[*attrs_len + 1];
    const unsigned old_attrs_len = *attrs_len;
    size_t total;

    if ((err = hal_ks_attribute_scan(bytes, bytes_len, attrs, *attrs_len, &total)) != HAL_OK)
      return err;

    err = hal_ks_attribute_insert(bytes, bytes_len, attrs, attrs_len, &total, type, value, value_len);

    if (*attrs_len != old_attrs_len && err != HAL_OK)
      cache_release(block);

    if (err == HAL_ERROR_RESULT_TOO_LONG)
      continue;

    if (err != HAL_OK)
      return err;

    return block_update(b, block, &slot->name, chunk, &hint);

  } while (++chunk < block->header.total_chunks);

  /*
   * If we get here, we have to add a new block, which requires
   * rewriting all the others to bump the total_blocks count.  We need
   * to keep track of all the old chunks so we can zero them at the
   * end, and because we can't zero them until we've written out the
   * new chunks, we need enough free blocks for the entire new object.
   */

  const unsigned total_chunks = block->header.total_chunks;
  unsigned b, blocks[total_chunks];

  if (db.ksi.used + total_chunks + 1 > db.ksi.size)
    return HAL_ERROR_NO_KEY_INDEX_SLOTS;

  for (chunk = 0; chunk < total_chunks; chunk++) {
    int hint = slot->hint + chunk;
    if ((err = hal_ks_index_find(&db.ksi, &slot->name, chunk, &blocks[chunk], &hint)) != HAL_OK ||
        (err = block_deprecate(blocks[chunk]))                                        != HAL_OK)
      return err;
  }

  {
    block = cache_pick_lru();

    memset(block, 0xFF, sizeof(*block));

    block->header.block_type   = BLOCK_TYPE_ATTR;
    block->header.block_status = BLOCK_STATUS_LIVE;
    block->header.total_chunks = total_chunks + 1;
    block->header.this_chunk   = total_chunks;
    block->attr.name = slot->name;
    block->attr.attributes_len = 0;

    hal_rpc_pkey_attribute_t attrs[1];
    size_t total = 0;

    if ((err = hal_ks_attribute_insert(block->attr.attributes,
                                       SIZEOF_FLASH_ATTRIBUTE_BLOCK_ATTRIBUTES,
                                       attrs, &block->attr.attributes_len, &total,
                                       type, value, value_len))                         != HAL_OK ||
        (err = hal_ks_index_add(&db.ksi, &slot->name, total_chunks, &b, NULL))          != HAL_OK ||
        (err = block_write(b, block))                                                   != HAL_OK)
      return err;

    cache_mark_used(block, b);
  }

  for (chunk = 0; chunk < total_chunks; chunk++) {
    int hint = slot->hint + chunk;
    if ((err = block_read_cached(blocks[chunk], &block)) != HAL_OK)
      return err;
    if (block->header.this_chunk != chunk)
      return HAL_ERROR_IMPOSSIBLE;
    block->header.block_status = BLOCK_STATUS_LIVE;
    block->header.total_chunks = total_chunks + 1;

    uint8_t *bytes = NULL;
    size_t bytes_len = 0;
    unsigned *attrs_len;
    size_t total;

    if ((err = locate_attributes(block, chunk, &bytes, &bytes_len, &attrs_len)) != HAL_OK)
      return err;

    if (*attrs_len > 0) {
      hal_rpc_pkey_attribute_t attrs[*attrs_len];
      if ((err = hal_ks_attribute_scan(bytes, bytes_len, attrs, *attrs_len, &total)) != HAL_OK ||
          (err = hal_ks_attribute_delete(bytes, bytes_len, attrs, attrs_len, &total, type)) != HAL_OK)
        return err;
    }

    unsigned b;

    if ((err = hal_ks_index_replace(&db.ksi, &slot->name, chunk, &b, &hint))    != HAL_OK ||
        (err = block_write(b, block))                                           != HAL_OK)
      return err;
  }

  for (chunk = 0; chunk < total_chunks; chunk++)
    if ((err = block_zero(blocks[chunk])) != HAL_OK)
      return err;

  return HAL_OK;
}

static  hal_error_t ks_get_attribute(hal_ks_t *ks,
                                     hal_pkey_slot_t *slot,
                                     const uint32_t type,
                                     uint8_t *value,
                                     size_t *value_len,
                                     const size_t value_max)
{
  if (ks != &db.ks || slot == NULL)
    return HAL_ERROR_BAD_ARGUMENTS;

  flash_block_t *block;
  hal_error_t err;
  unsigned b;

  hal_rpc_pkey_attribute_t a = {0, 0, NULL};
  unsigned chunk = 0;

  do {
    int hint = slot->hint + chunk;

    if ((err = hal_ks_index_find(&db.ksi, &slot->name, chunk, &b, &hint)) != HAL_OK ||
        (err = block_read_cached(b, &block))                              != HAL_OK)
      return err;

    if (block->header.this_chunk != chunk)
      return HAL_ERROR_IMPOSSIBLE;

    if (chunk == 0)
      slot->hint = hint;

    cache_mark_used(block, b);

    uint8_t *bytes = NULL;
    size_t bytes_len = 0;
    unsigned *attrs_len;

    if ((err = locate_attributes(block, chunk, &bytes, &bytes_len, &attrs_len)) != HAL_OK)
      return err;

    if (*attrs_len == 0)
      continue;

    hal_rpc_pkey_attribute_t attrs[*attrs_len];

    if ((err = hal_ks_attribute_scan(bytes, bytes_len, attrs, *attrs_len, NULL)) != HAL_OK)
      return err;

    for (int i = 0; a.value == NULL && i < *attrs_len; ++i)
      if (attrs[i].type == type)
        a = attrs[i];

  } while (a.value == NULL && ++chunk < block->header.total_chunks);

  if (a.value == NULL)
    return HAL_ERROR_ATTRIBUTE_NOT_FOUND;

  if (a.length > value_max && value != NULL)
    return HAL_ERROR_RESULT_TOO_LONG;

  if (value != NULL)
    memcpy(value, a.value, a.length);

  if (value_len != NULL)
    *value_len = a.length;

  return HAL_OK;
}

static hal_error_t ks_delete_attribute(hal_ks_t *ks,
                                       hal_pkey_slot_t *slot,
                                       const uint32_t type)
{
  /*
   * For extra credit, we could handle attribute compaction here, but
   * in practice we expect attribute deletion without deleting the
   * entire object to be a rare enough event that it may not be worth
   * it.  Certainly it's not a high priority, so later, if ever.
   */

  if (ks != &db.ks || slot == NULL)
    return HAL_ERROR_BAD_ARGUMENTS;

  flash_block_t *block;
  unsigned chunk = 0;

  do {
    int hint = slot->hint + chunk;
    hal_error_t err;
    unsigned b;

    if ((err = hal_ks_index_find(&db.ksi, &slot->name, chunk, &b, &hint)) != HAL_OK ||
        (err = block_read_cached(b, &block))                              != HAL_OK)
      return err;

    if (block->header.this_chunk != chunk)
      return HAL_ERROR_IMPOSSIBLE;

    if (chunk == 0)
      slot->hint = hint;

    uint8_t *bytes = NULL;
    size_t bytes_len = 0;
    unsigned *attrs_len;

    if ((err = locate_attributes(block, chunk, &bytes, &bytes_len, &attrs_len)) != HAL_OK)
      return err;

    cache_mark_used(block, b);

    if (*attrs_len == 0)
      continue;

    hal_rpc_pkey_attribute_t attrs[*attrs_len];
    const unsigned old_attrs_len = *attrs_len;
    size_t total;

    if ((err = hal_ks_attribute_scan(  bytes, bytes_len, attrs, *attrs_len, &total))       != HAL_OK ||
        (err = hal_ks_attribute_delete(bytes, bytes_len, attrs,  attrs_len, &total, type)) != HAL_OK)
      return err;

    if (*attrs_len == old_attrs_len)
      continue;

    if ((err = block_update(b, block, &slot->name, chunk, &hint)) != HAL_OK)
      return err;

  } while (++chunk < block->header.total_chunks);

  return HAL_OK;
}

const hal_ks_driver_t hal_ks_token_driver[1] = {{
  ks_init,
  ks_shutdown,
  ks_open,
  ks_close,
  ks_store,
  ks_fetch,
  ks_delete,
  ks_list,
  ks_match,
  ks_set_attribute,
  ks_get_attribute,
  ks_delete_attribute
}};

/*
 * The remaining functions aren't really part of the keystore API per se,
 * but they all involve non-key data which we keep in the keystore
 * because it's the flash we've got.
 */

/*
 * Fetch PIN.  This is always cached, so just returned cached value.
 */

hal_error_t hal_get_pin(const hal_user_t user,
                        const hal_ks_pin_t **pin)
{
  if (pin == NULL)
    return HAL_ERROR_BAD_ARGUMENTS;

  switch (user) {
  case HAL_USER_WHEEL:  *pin = &db.wheel_pin;  break;
  case HAL_USER_SO:     *pin = &db.so_pin;     break;
  case HAL_USER_NORMAL: *pin = &db.user_pin;   break;
  default:              return HAL_ERROR_BAD_ARGUMENTS;
  }

  return HAL_OK;
}

/*
 * Fetch PIN block.  hint = 0 because we know that the all-zeros UUID
 * should always sort to first slot in the index.
 */

static hal_error_t fetch_pin_block(unsigned *b, flash_block_t **block)
{
  if (block == NULL)
    return HAL_ERROR_IMPOSSIBLE;

  hal_error_t err;
  int hint = 0;
  unsigned b_;

  if (b == NULL)
    b = &b_;

  if ((err = hal_ks_index_find(&db.ksi, &pin_uuid, 0, b, &hint)) != HAL_OK ||
      (err = block_read_cached(*b, block))                       != HAL_OK)
    return err;

  cache_mark_used(*block, *b);

  if (block_get_type(*block) != BLOCK_TYPE_PIN)
    return HAL_ERROR_IMPOSSIBLE;

  return HAL_OK;
}

/*
 * Update the PIN block.  This block should always be present, but we
 * have to do the zombie jamboree to make sure we write the new PIN
 * block before destroying the old one.  hint = 0 because we know that
 * the all-zeros UUID should always sort to first slot in the index.
 */

static hal_error_t update_pin_block(const unsigned b,
                                    flash_block_t *block,
                                    const flash_pin_block_t * const new_data)
{
  if (block == NULL || new_data == NULL || block_get_type(block) != BLOCK_TYPE_PIN)
    return HAL_ERROR_IMPOSSIBLE;

  int hint = 0;

  block->pin = *new_data;

  return block_update(b, block, &pin_uuid, 0, &hint);
}

/*
 * Change a PIN.
 */

hal_error_t hal_set_pin(const hal_user_t user,
                        const hal_ks_pin_t * const pin)
{
  if (pin == NULL)
    return HAL_ERROR_BAD_ARGUMENTS;

  flash_block_t *block;
  hal_error_t err;
  unsigned b;

  if ((err = fetch_pin_block(&b, &block)) != HAL_OK)
    return err;

  flash_pin_block_t new_data = block->pin;
  hal_ks_pin_t *dp, *bp;

  switch (user) {
  case HAL_USER_WHEEL:  bp = &new_data.wheel_pin; dp = &db.wheel_pin; break;
  case HAL_USER_SO:     bp = &new_data.so_pin;    dp = &db.so_pin;    break;
  case HAL_USER_NORMAL: bp = &new_data.user_pin;  dp = &db.user_pin;  break;
  default:              return HAL_ERROR_BAD_ARGUMENTS;
  }

  const hal_ks_pin_t old_pin = *dp;
  *dp = *bp = *pin;

  if ((err = update_pin_block(b, block, &new_data)) != HAL_OK)
    *dp = old_pin;

  return err;
}

#if HAL_MKM_FLASH_BACKUP_KLUDGE

/*
 * Horrible insecure kludge in lieu of a battery for the MKM.
 *
 * API here is a little strange: all calls pass a length parameter,
 * but any length other than the compiled in constant just returns an
 * immediate error, there's no notion of buffer max length vs buffer
 * used length, querying for the size of buffer really needed, or
 * anything like that.
 *
 * We might want to rewrite this some day, if we don't replace it with
 * a battery first.  For now we just preserve the API as we found it
 * while re-implementing it on top of the new keystore.
 */

hal_error_t hal_mkm_flash_read(uint8_t *buf, const size_t len)
{
  if (buf != NULL && len != KEK_LENGTH)
    return HAL_ERROR_MASTERKEY_BAD_LENGTH;

  flash_block_t *block;
  hal_error_t err;
  unsigned b;

  if ((err = fetch_pin_block(&b, &block)) != HAL_OK)
    return err;

  if (block->pin.kek_set != FLASH_KEK_SET)
    return HAL_ERROR_MASTERKEY_NOT_SET;

  if (buf != NULL)
    memcpy(buf, block->pin.kek, len);

  return HAL_OK;
}

hal_error_t hal_mkm_flash_write(const uint8_t * const buf, const size_t len)
{
  if (buf == NULL)
    return HAL_ERROR_BAD_ARGUMENTS;

  if (len != KEK_LENGTH)
    return HAL_ERROR_MASTERKEY_BAD_LENGTH;

  flash_block_t *block;
  hal_error_t err;
  unsigned b;

  if ((err = fetch_pin_block(&b, &block)) != HAL_OK)
    return err;

  flash_pin_block_t new_data = block->pin;

  new_data.kek_set = FLASH_KEK_SET;
  memcpy(new_data.kek, buf, len);

  return update_pin_block(b, block, &new_data);
}

hal_error_t hal_mkm_flash_erase(const size_t len)
{
  if (len != KEK_LENGTH)
    return HAL_ERROR_MASTERKEY_BAD_LENGTH;

  flash_block_t *block;
  hal_error_t err;
  unsigned b;

  if ((err = fetch_pin_block(&b, &block)) != HAL_OK)
    return err;

  flash_pin_block_t new_data = block->pin;

  new_data.kek_set = FLASH_KEK_SET;
  memset(new_data.kek, 0, len);

  return update_pin_block(b, block, &new_data);
}

#endif /* HAL_MKM_FLASH_BACKUP_KLUDGE */


/*
 * Local variables:
 * indent-tabs-mode: nil
 * End:
 */
an>(q15_t) y))) << 16) + clip_q31_to_q15((q31_t) ((q15_t) x - (q15_t) (y >> 16))); return sum; } /* * @brief C custom defined SHASX for M3 and M0 processors */ static __INLINE q31_t __SHASX( q31_t x, q31_t y) { q31_t sum; q31_t r, s; r = (q15_t) x; s = (q15_t) y; r = ((r >> 1) - (y >> 17)); s = (((x >> 17) + (s >> 1)) << 16); sum = (s & 0xFFFF0000) | (r & 0x0000FFFF); return sum; } /* * @brief C custom defined QSAX for M3 and M0 processors */ static __INLINE q31_t __QSAX( q31_t x, q31_t y) { q31_t sum = 0; sum = ((sum + clip_q31_to_q15((q31_t) ((q15_t) (x >> 16) - (q15_t) y))) << 16) + clip_q31_to_q15((q31_t) ((q15_t) x + (q15_t) (y >> 16))); return sum; } /* * @brief C custom defined SHSAX for M3 and M0 processors */ static __INLINE q31_t __SHSAX( q31_t x, q31_t y) { q31_t sum; q31_t r, s; r = (q15_t) x; s = (q15_t) y; r = ((r >> 1) + (y >> 17)); s = (((x >> 17) - (s >> 1)) << 16); sum = (s & 0xFFFF0000) | (r & 0x0000FFFF); return sum; } /* * @brief C custom defined SMUSDX for M3 and M0 processors */ static __INLINE q31_t __SMUSDX( q31_t x, q31_t y) { return ((q31_t) (((q15_t) x * (q15_t) (y >> 16)) - ((q15_t) (x >> 16) * (q15_t) y))); } /* * @brief C custom defined SMUADX for M3 and M0 processors */ static __INLINE q31_t __SMUADX( q31_t x, q31_t y) { return ((q31_t) (((q15_t) x * (q15_t) (y >> 16)) + ((q15_t) (x >> 16) * (q15_t) y))); } /* * @brief C custom defined QADD for M3 and M0 processors */ static __INLINE q31_t __QADD( q31_t x, q31_t y) { return clip_q63_to_q31((q63_t) x + y); } /* * @brief C custom defined QSUB for M3 and M0 processors */ static __INLINE q31_t __QSUB( q31_t x, q31_t y) { return clip_q63_to_q31((q63_t) x - y); } /* * @brief C custom defined SMLAD for M3 and M0 processors */ static __INLINE q31_t __SMLAD( q31_t x, q31_t y, q31_t sum) { return (sum + ((q15_t) (x >> 16) * (q15_t) (y >> 16)) + ((q15_t) x * (q15_t) y)); } /* * @brief C custom defined SMLADX for M3 and M0 processors */ static __INLINE q31_t __SMLADX( q31_t x, q31_t y, q31_t sum) { return (sum + ((q15_t) (x >> 16) * (q15_t) (y)) + ((q15_t) x * (q15_t) (y >> 16))); } /* * @brief C custom defined SMLSDX for M3 and M0 processors */ static __INLINE q31_t __SMLSDX( q31_t x, q31_t y, q31_t sum) { return (sum - ((q15_t) (x >> 16) * (q15_t) (y)) + ((q15_t) x * (q15_t) (y >> 16))); } /* * @brief C custom defined SMLALD for M3 and M0 processors */ static __INLINE q63_t __SMLALD( q31_t x, q31_t y, q63_t sum) { return (sum + ((q15_t) (x >> 16) * (q15_t) (y >> 16)) + ((q15_t) x * (q15_t) y)); } /* * @brief C custom defined SMLALDX for M3 and M0 processors */ static __INLINE q63_t __SMLALDX( q31_t x, q31_t y, q63_t sum) { return (sum + ((q15_t) (x >> 16) * (q15_t) y)) + ((q15_t) x * (q15_t) (y >> 16)); } /* * @brief C custom defined SMUAD for M3 and M0 processors */ static __INLINE q31_t __SMUAD( q31_t x, q31_t y) { return (((x >> 16) * (y >> 16)) + (((x << 16) >> 16) * ((y << 16) >> 16))); } /* * @brief C custom defined SMUSD for M3 and M0 processors */ static __INLINE q31_t __SMUSD( q31_t x, q31_t y) { return (-((x >> 16) * (y >> 16)) + (((x << 16) >> 16) * ((y << 16) >> 16))); } /* * @brief C custom defined SXTB16 for M3 and M0 processors */ static __INLINE q31_t __SXTB16( q31_t x) { return ((((x << 24) >> 24) & 0x0000FFFF) | (((x << 8) >> 8) & 0xFFFF0000)); } #endif /* defined (ARM_MATH_CM3) || defined (ARM_MATH_CM0_FAMILY) */ /** * @brief Instance structure for the Q7 FIR filter. */ typedef struct { uint16_t numTaps; /**< number of filter coefficients in the filter. */ q7_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ q7_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps.*/ } arm_fir_instance_q7; /** * @brief Instance structure for the Q15 FIR filter. */ typedef struct { uint16_t numTaps; /**< number of filter coefficients in the filter. */ q15_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ q15_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps.*/ } arm_fir_instance_q15; /** * @brief Instance structure for the Q31 FIR filter. */ typedef struct { uint16_t numTaps; /**< number of filter coefficients in the filter. */ q31_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ q31_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps. */ } arm_fir_instance_q31; /** * @brief Instance structure for the floating-point FIR filter. */ typedef struct { uint16_t numTaps; /**< number of filter coefficients in the filter. */ float32_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ float32_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps. */ } arm_fir_instance_f32; /** * @brief Processing function for the Q7 FIR filter. * @param[in] *S points to an instance of the Q7 FIR filter structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_fir_q7( const arm_fir_instance_q7 * S, q7_t * pSrc, q7_t * pDst, uint32_t blockSize); /** * @brief Initialization function for the Q7 FIR filter. * @param[in,out] *S points to an instance of the Q7 FIR structure. * @param[in] numTaps Number of filter coefficients in the filter. * @param[in] *pCoeffs points to the filter coefficients. * @param[in] *pState points to the state buffer. * @param[in] blockSize number of samples that are processed. * @return none */ void arm_fir_init_q7( arm_fir_instance_q7 * S, uint16_t numTaps, q7_t * pCoeffs, q7_t * pState, uint32_t blockSize); /** * @brief Processing function for the Q15 FIR filter. * @param[in] *S points to an instance of the Q15 FIR structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_fir_q15( const arm_fir_instance_q15 * S, q15_t * pSrc, q15_t * pDst, uint32_t blockSize); /** * @brief Processing function for the fast Q15 FIR filter for Cortex-M3 and Cortex-M4. * @param[in] *S points to an instance of the Q15 FIR filter structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_fir_fast_q15( const arm_fir_instance_q15 * S, q15_t * pSrc, q15_t * pDst, uint32_t blockSize); /** * @brief Initialization function for the Q15 FIR filter. * @param[in,out] *S points to an instance of the Q15 FIR filter structure. * @param[in] numTaps Number of filter coefficients in the filter. Must be even and greater than or equal to 4. * @param[in] *pCoeffs points to the filter coefficients. * @param[in] *pState points to the state buffer. * @param[in] blockSize number of samples that are processed at a time. * @return The function returns ARM_MATH_SUCCESS if initialization was successful or ARM_MATH_ARGUMENT_ERROR if * <code>numTaps</code> is not a supported value. */ arm_status arm_fir_init_q15( arm_fir_instance_q15 * S, uint16_t numTaps, q15_t * pCoeffs, q15_t * pState, uint32_t blockSize); /** * @brief Processing function for the Q31 FIR filter. * @param[in] *S points to an instance of the Q31 FIR filter structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_fir_q31( const arm_fir_instance_q31 * S, q31_t * pSrc, q31_t * pDst, uint32_t blockSize); /** * @brief Processing function for the fast Q31 FIR filter for Cortex-M3 and Cortex-M4. * @param[in] *S points to an instance of the Q31 FIR structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_fir_fast_q31( const arm_fir_instance_q31 * S, q31_t * pSrc, q31_t * pDst, uint32_t blockSize); /** * @brief Initialization function for the Q31 FIR filter. * @param[in,out] *S points to an instance of the Q31 FIR structure. * @param[in] numTaps Number of filter coefficients in the filter. * @param[in] *pCoeffs points to the filter coefficients. * @param[in] *pState points to the state buffer. * @param[in] blockSize number of samples that are processed at a time. * @return none. */ void arm_fir_init_q31( arm_fir_instance_q31 * S, uint16_t numTaps, q31_t * pCoeffs, q31_t * pState, uint32_t blockSize); /** * @brief Processing function for the floating-point FIR filter. * @param[in] *S points to an instance of the floating-point FIR structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_fir_f32( const arm_fir_instance_f32 * S, float32_t * pSrc, float32_t * pDst, uint32_t blockSize); /** * @brief Initialization function for the floating-point FIR filter. * @param[in,out] *S points to an instance of the floating-point FIR filter structure. * @param[in] numTaps Number of filter coefficients in the filter. * @param[in] *pCoeffs points to the filter coefficients. * @param[in] *pState points to the state buffer. * @param[in] blockSize number of samples that are processed at a time. * @return none. */ void arm_fir_init_f32( arm_fir_instance_f32 * S, uint16_t numTaps, float32_t * pCoeffs, float32_t * pState, uint32_t blockSize); /** * @brief Instance structure for the Q15 Biquad cascade filter. */ typedef struct { int8_t numStages; /**< number of 2nd order stages in the filter. Overall order is 2*numStages. */ q15_t *pState; /**< Points to the array of state coefficients. The array is of length 4*numStages. */ q15_t *pCoeffs; /**< Points to the array of coefficients. The array is of length 5*numStages. */ int8_t postShift; /**< Additional shift, in bits, applied to each output sample. */ } arm_biquad_casd_df1_inst_q15; /** * @brief Instance structure for the Q31 Biquad cascade filter. */ typedef struct { uint32_t numStages; /**< number of 2nd order stages in the filter. Overall order is 2*numStages. */ q31_t *pState; /**< Points to the array of state coefficients. The array is of length 4*numStages. */ q31_t *pCoeffs; /**< Points to the array of coefficients. The array is of length 5*numStages. */ uint8_t postShift; /**< Additional shift, in bits, applied to each output sample. */ } arm_biquad_casd_df1_inst_q31; /** * @brief Instance structure for the floating-point Biquad cascade filter. */ typedef struct { uint32_t numStages; /**< number of 2nd order stages in the filter. Overall order is 2*numStages. */ float32_t *pState; /**< Points to the array of state coefficients. The array is of length 4*numStages. */ float32_t *pCoeffs; /**< Points to the array of coefficients. The array is of length 5*numStages. */ } arm_biquad_casd_df1_inst_f32; /** * @brief Processing function for the Q15 Biquad cascade filter. * @param[in] *S points to an instance of the Q15 Biquad cascade structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_biquad_cascade_df1_q15( const arm_biquad_casd_df1_inst_q15 * S, q15_t * pSrc, q15_t * pDst, uint32_t blockSize); /** * @brief Initialization function for the Q15 Biquad cascade filter. * @param[in,out] *S points to an instance of the Q15 Biquad cascade structure. * @param[in] numStages number of 2nd order stages in the filter. * @param[in] *pCoeffs points to the filter coefficients. * @param[in] *pState points to the state buffer. * @param[in] postShift Shift to be applied to the output. Varies according to the coefficients format * @return none */ void arm_biquad_cascade_df1_init_q15( arm_biquad_casd_df1_inst_q15 * S, uint8_t numStages, q15_t * pCoeffs, q15_t * pState, int8_t postShift); /** * @brief Fast but less precise processing function for the Q15 Biquad cascade filter for Cortex-M3 and Cortex-M4. * @param[in] *S points to an instance of the Q15 Biquad cascade structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_biquad_cascade_df1_fast_q15( const arm_biquad_casd_df1_inst_q15 * S, q15_t * pSrc, q15_t * pDst, uint32_t blockSize); /** * @brief Processing function for the Q31 Biquad cascade filter * @param[in] *S points to an instance of the Q31 Biquad cascade structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_biquad_cascade_df1_q31( const arm_biquad_casd_df1_inst_q31 * S, q31_t * pSrc, q31_t * pDst, uint32_t blockSize); /** * @brief Fast but less precise processing function for the Q31 Biquad cascade filter for Cortex-M3 and Cortex-M4. * @param[in] *S points to an instance of the Q31 Biquad cascade structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_biquad_cascade_df1_fast_q31( const arm_biquad_casd_df1_inst_q31 * S, q31_t * pSrc, q31_t * pDst, uint32_t blockSize); /** * @brief Initialization function for the Q31 Biquad cascade filter. * @param[in,out] *S points to an instance of the Q31 Biquad cascade structure. * @param[in] numStages number of 2nd order stages in the filter. * @param[in] *pCoeffs points to the filter coefficients. * @param[in] *pState points to the state buffer. * @param[in] postShift Shift to be applied to the output. Varies according to the coefficients format * @return none */ void arm_biquad_cascade_df1_init_q31( arm_biquad_casd_df1_inst_q31 * S, uint8_t numStages, q31_t * pCoeffs, q31_t * pState, int8_t postShift); /** * @brief Processing function for the floating-point Biquad cascade filter. * @param[in] *S points to an instance of the floating-point Biquad cascade structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_biquad_cascade_df1_f32( const arm_biquad_casd_df1_inst_f32 * S, float32_t * pSrc, float32_t * pDst, uint32_t blockSize); /** * @brief Initialization function for the floating-point Biquad cascade filter. * @param[in,out] *S points to an instance of the floating-point Biquad cascade structure. * @param[in] numStages number of 2nd order stages in the filter. * @param[in] *pCoeffs points to the filter coefficients. * @param[in] *pState points to the state buffer. * @return none */ void arm_biquad_cascade_df1_init_f32( arm_biquad_casd_df1_inst_f32 * S, uint8_t numStages, float32_t * pCoeffs, float32_t * pState); /** * @brief Instance structure for the floating-point matrix structure. */ typedef struct { uint16_t numRows; /**< number of rows of the matrix. */ uint16_t numCols; /**< number of columns of the matrix. */ float32_t *pData; /**< points to the data of the matrix. */ } arm_matrix_instance_f32; /** * @brief Instance structure for the floating-point matrix structure. */ typedef struct { uint16_t numRows; /**< number of rows of the matrix. */ uint16_t numCols; /**< number of columns of the matrix. */ float64_t *pData; /**< points to the data of the matrix. */ } arm_matrix_instance_f64; /** * @brief Instance structure for the Q15 matrix structure. */ typedef struct { uint16_t numRows; /**< number of rows of the matrix. */ uint16_t numCols; /**< number of columns of the matrix. */ q15_t *pData; /**< points to the data of the matrix. */ } arm_matrix_instance_q15; /** * @brief Instance structure for the Q31 matrix structure. */ typedef struct { uint16_t numRows; /**< number of rows of the matrix. */ uint16_t numCols; /**< number of columns of the matrix. */ q31_t *pData; /**< points to the data of the matrix. */ } arm_matrix_instance_q31; /** * @brief Floating-point matrix addition. * @param[in] *pSrcA points to the first input matrix structure * @param[in] *pSrcB points to the second input matrix structure * @param[out] *pDst points to output matrix structure * @return The function returns either * <code>ARM_MATH_SIZE_MISMATCH</code> or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_add_f32( const arm_matrix_instance_f32 * pSrcA, const arm_matrix_instance_f32 * pSrcB, arm_matrix_instance_f32 * pDst); /** * @brief Q15 matrix addition. * @param[in] *pSrcA points to the first input matrix structure * @param[in] *pSrcB points to the second input matrix structure * @param[out] *pDst points to output matrix structure * @return The function returns either * <code>ARM_MATH_SIZE_MISMATCH</code> or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_add_q15( const arm_matrix_instance_q15 * pSrcA, const arm_matrix_instance_q15 * pSrcB, arm_matrix_instance_q15 * pDst); /** * @brief Q31 matrix addition. * @param[in] *pSrcA points to the first input matrix structure * @param[in] *pSrcB points to the second input matrix structure * @param[out] *pDst points to output matrix structure * @return The function returns either * <code>ARM_MATH_SIZE_MISMATCH</code> or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_add_q31( const arm_matrix_instance_q31 * pSrcA, const arm_matrix_instance_q31 * pSrcB, arm_matrix_instance_q31 * pDst); /** * @brief Floating-point, complex, matrix multiplication. * @param[in] *pSrcA points to the first input matrix structure * @param[in] *pSrcB points to the second input matrix structure * @param[out] *pDst points to output matrix structure * @return The function returns either * <code>ARM_MATH_SIZE_MISMATCH</code> or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_cmplx_mult_f32( const arm_matrix_instance_f32 * pSrcA, const arm_matrix_instance_f32 * pSrcB, arm_matrix_instance_f32 * pDst); /** * @brief Q15, complex, matrix multiplication. * @param[in] *pSrcA points to the first input matrix structure * @param[in] *pSrcB points to the second input matrix structure * @param[out] *pDst points to output matrix structure * @return The function returns either * <code>ARM_MATH_SIZE_MISMATCH</code> or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_cmplx_mult_q15( const arm_matrix_instance_q15 * pSrcA, const arm_matrix_instance_q15 * pSrcB, arm_matrix_instance_q15 * pDst, q15_t * pScratch); /** * @brief Q31, complex, matrix multiplication. * @param[in] *pSrcA points to the first input matrix structure * @param[in] *pSrcB points to the second input matrix structure * @param[out] *pDst points to output matrix structure * @return The function returns either * <code>ARM_MATH_SIZE_MISMATCH</code> or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_cmplx_mult_q31( const arm_matrix_instance_q31 * pSrcA, const arm_matrix_instance_q31 * pSrcB, arm_matrix_instance_q31 * pDst); /** * @brief Floating-point matrix transpose. * @param[in] *pSrc points to the input matrix * @param[out] *pDst points to the output matrix * @return The function returns either <code>ARM_MATH_SIZE_MISMATCH</code> * or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_trans_f32( const arm_matrix_instance_f32 * pSrc, arm_matrix_instance_f32 * pDst); /** * @brief Q15 matrix transpose. * @param[in] *pSrc points to the input matrix * @param[out] *pDst points to the output matrix * @return The function returns either <code>ARM_MATH_SIZE_MISMATCH</code> * or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_trans_q15( const arm_matrix_instance_q15 * pSrc, arm_matrix_instance_q15 * pDst); /** * @brief Q31 matrix transpose. * @param[in] *pSrc points to the input matrix * @param[out] *pDst points to the output matrix * @return The function returns either <code>ARM_MATH_SIZE_MISMATCH</code> * or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_trans_q31( const arm_matrix_instance_q31 * pSrc, arm_matrix_instance_q31 * pDst); /** * @brief Floating-point matrix multiplication * @param[in] *pSrcA points to the first input matrix structure * @param[in] *pSrcB points to the second input matrix structure * @param[out] *pDst points to output matrix structure * @return The function returns either * <code>ARM_MATH_SIZE_MISMATCH</code> or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_mult_f32( const arm_matrix_instance_f32 * pSrcA, const arm_matrix_instance_f32 * pSrcB, arm_matrix_instance_f32 * pDst); /** * @brief Q15 matrix multiplication * @param[in] *pSrcA points to the first input matrix structure * @param[in] *pSrcB points to the second input matrix structure * @param[out] *pDst points to output matrix structure * @param[in] *pState points to the array for storing intermediate results * @return The function returns either * <code>ARM_MATH_SIZE_MISMATCH</code> or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_mult_q15( const arm_matrix_instance_q15 * pSrcA, const arm_matrix_instance_q15 * pSrcB, arm_matrix_instance_q15 * pDst, q15_t * pState); /** * @brief Q15 matrix multiplication (fast variant) for Cortex-M3 and Cortex-M4 * @param[in] *pSrcA points to the first input matrix structure * @param[in] *pSrcB points to the second input matrix structure * @param[out] *pDst points to output matrix structure * @param[in] *pState points to the array for storing intermediate results * @return The function returns either * <code>ARM_MATH_SIZE_MISMATCH</code> or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_mult_fast_q15( const arm_matrix_instance_q15 * pSrcA, const arm_matrix_instance_q15 * pSrcB, arm_matrix_instance_q15 * pDst, q15_t * pState); /** * @brief Q31 matrix multiplication * @param[in] *pSrcA points to the first input matrix structure * @param[in] *pSrcB points to the second input matrix structure * @param[out] *pDst points to output matrix structure * @return The function returns either * <code>ARM_MATH_SIZE_MISMATCH</code> or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_mult_q31( const arm_matrix_instance_q31 * pSrcA, const arm_matrix_instance_q31 * pSrcB, arm_matrix_instance_q31 * pDst); /** * @brief Q31 matrix multiplication (fast variant) for Cortex-M3 and Cortex-M4 * @param[in] *pSrcA points to the first input matrix structure * @param[in] *pSrcB points to the second input matrix structure * @param[out] *pDst points to output matrix structure * @return The function returns either * <code>ARM_MATH_SIZE_MISMATCH</code> or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_mult_fast_q31( const arm_matrix_instance_q31 * pSrcA, const arm_matrix_instance_q31 * pSrcB, arm_matrix_instance_q31 * pDst); /** * @brief Floating-point matrix subtraction * @param[in] *pSrcA points to the first input matrix structure * @param[in] *pSrcB points to the second input matrix structure * @param[out] *pDst points to output matrix structure * @return The function returns either * <code>ARM_MATH_SIZE_MISMATCH</code> or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_sub_f32( const arm_matrix_instance_f32 * pSrcA, const arm_matrix_instance_f32 * pSrcB, arm_matrix_instance_f32 * pDst); /** * @brief Q15 matrix subtraction * @param[in] *pSrcA points to the first input matrix structure * @param[in] *pSrcB points to the second input matrix structure * @param[out] *pDst points to output matrix structure * @return The function returns either * <code>ARM_MATH_SIZE_MISMATCH</code> or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_sub_q15( const arm_matrix_instance_q15 * pSrcA, const arm_matrix_instance_q15 * pSrcB, arm_matrix_instance_q15 * pDst); /** * @brief Q31 matrix subtraction * @param[in] *pSrcA points to the first input matrix structure * @param[in] *pSrcB points to the second input matrix structure * @param[out] *pDst points to output matrix structure * @return The function returns either * <code>ARM_MATH_SIZE_MISMATCH</code> or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_sub_q31( const arm_matrix_instance_q31 * pSrcA, const arm_matrix_instance_q31 * pSrcB, arm_matrix_instance_q31 * pDst); /** * @brief Floating-point matrix scaling. * @param[in] *pSrc points to the input matrix * @param[in] scale scale factor * @param[out] *pDst points to the output matrix * @return The function returns either * <code>ARM_MATH_SIZE_MISMATCH</code> or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_scale_f32( const arm_matrix_instance_f32 * pSrc, float32_t scale, arm_matrix_instance_f32 * pDst); /** * @brief Q15 matrix scaling. * @param[in] *pSrc points to input matrix * @param[in] scaleFract fractional portion of the scale factor * @param[in] shift number of bits to shift the result by * @param[out] *pDst points to output matrix * @return The function returns either * <code>ARM_MATH_SIZE_MISMATCH</code> or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_scale_q15( const arm_matrix_instance_q15 * pSrc, q15_t scaleFract, int32_t shift, arm_matrix_instance_q15 * pDst); /** * @brief Q31 matrix scaling. * @param[in] *pSrc points to input matrix * @param[in] scaleFract fractional portion of the scale factor * @param[in] shift number of bits to shift the result by * @param[out] *pDst points to output matrix structure * @return The function returns either * <code>ARM_MATH_SIZE_MISMATCH</code> or <code>ARM_MATH_SUCCESS</code> based on the outcome of size checking. */ arm_status arm_mat_scale_q31( const arm_matrix_instance_q31 * pSrc, q31_t scaleFract, int32_t shift, arm_matrix_instance_q31 * pDst); /** * @brief Q31 matrix initialization. * @param[in,out] *S points to an instance of the floating-point matrix structure. * @param[in] nRows number of rows in the matrix. * @param[in] nColumns number of columns in the matrix. * @param[in] *pData points to the matrix data array. * @return none */ void arm_mat_init_q31( arm_matrix_instance_q31 * S, uint16_t nRows, uint16_t nColumns, q31_t * pData); /** * @brief Q15 matrix initialization. * @param[in,out] *S points to an instance of the floating-point matrix structure. * @param[in] nRows number of rows in the matrix. * @param[in] nColumns number of columns in the matrix. * @param[in] *pData points to the matrix data array. * @return none */ void arm_mat_init_q15( arm_matrix_instance_q15 * S, uint16_t nRows, uint16_t nColumns, q15_t * pData); /** * @brief Floating-point matrix initialization. * @param[in,out] *S points to an instance of the floating-point matrix structure. * @param[in] nRows number of rows in the matrix. * @param[in] nColumns number of columns in the matrix. * @param[in] *pData points to the matrix data array. * @return none */ void arm_mat_init_f32( arm_matrix_instance_f32 * S, uint16_t nRows, uint16_t nColumns, float32_t * pData); /** * @brief Instance structure for the Q15 PID Control. */ typedef struct { q15_t A0; /**< The derived gain, A0 = Kp + Ki + Kd . */ #ifdef ARM_MATH_CM0_FAMILY q15_t A1; q15_t A2; #else q31_t A1; /**< The derived gain A1 = -Kp - 2Kd | Kd.*/ #endif q15_t state[3]; /**< The state array of length 3. */ q15_t Kp; /**< The proportional gain. */ q15_t Ki; /**< The integral gain. */ q15_t Kd; /**< The derivative gain. */ } arm_pid_instance_q15; /** * @brief Instance structure for the Q31 PID Control. */ typedef struct { q31_t A0; /**< The derived gain, A0 = Kp + Ki + Kd . */ q31_t A1; /**< The derived gain, A1 = -Kp - 2Kd. */ q31_t A2; /**< The derived gain, A2 = Kd . */ q31_t state[3]; /**< The state array of length 3. */ q31_t Kp; /**< The proportional gain. */ q31_t Ki; /**< The integral gain. */ q31_t Kd; /**< The derivative gain. */ } arm_pid_instance_q31; /** * @brief Instance structure for the floating-point PID Control. */ typedef struct { float32_t A0; /**< The derived gain, A0 = Kp + Ki + Kd . */ float32_t A1; /**< The derived gain, A1 = -Kp - 2Kd. */ float32_t A2; /**< The derived gain, A2 = Kd . */ float32_t state[3]; /**< The state array of length 3. */ float32_t Kp; /**< The proportional gain. */ float32_t Ki; /**< The integral gain. */ float32_t Kd; /**< The derivative gain. */ } arm_pid_instance_f32; /** * @brief Initialization function for the floating-point PID Control. * @param[in,out] *S points to an instance of the PID structure. * @param[in] resetStateFlag flag to reset the state. 0 = no change in state 1 = reset the state. * @return none. */ void arm_pid_init_f32( arm_pid_instance_f32 * S, int32_t resetStateFlag); /** * @brief Reset function for the floating-point PID Control. * @param[in,out] *S is an instance of the floating-point PID Control structure * @return none */ void arm_pid_reset_f32( arm_pid_instance_f32 * S); /** * @brief Initialization function for the Q31 PID Control. * @param[in,out] *S points to an instance of the Q15 PID structure. * @param[in] resetStateFlag flag to reset the state. 0 = no change in state 1 = reset the state. * @return none. */ void arm_pid_init_q31( arm_pid_instance_q31 * S, int32_t resetStateFlag); /** * @brief Reset function for the Q31 PID Control. * @param[in,out] *S points to an instance of the Q31 PID Control structure * @return none */ void arm_pid_reset_q31( arm_pid_instance_q31 * S); /** * @brief Initialization function for the Q15 PID Control. * @param[in,out] *S points to an instance of the Q15 PID structure. * @param[in] resetStateFlag flag to reset the state. 0 = no change in state 1 = reset the state. * @return none. */ void arm_pid_init_q15( arm_pid_instance_q15 * S, int32_t resetStateFlag); /** * @brief Reset function for the Q15 PID Control. * @param[in,out] *S points to an instance of the q15 PID Control structure * @return none */ void arm_pid_reset_q15( arm_pid_instance_q15 * S); /** * @brief Instance structure for the floating-point Linear Interpolate function. */ typedef struct { uint32_t nValues; /**< nValues */ float32_t x1; /**< x1 */ float32_t xSpacing; /**< xSpacing */ float32_t *pYData; /**< pointer to the table of Y values */ } arm_linear_interp_instance_f32; /** * @brief Instance structure for the floating-point bilinear interpolation function. */ typedef struct { uint16_t numRows; /**< number of rows in the data table. */ uint16_t numCols; /**< number of columns in the data table. */ float32_t *pData; /**< points to the data table. */ } arm_bilinear_interp_instance_f32; /** * @brief Instance structure for the Q31 bilinear interpolation function. */ typedef struct { uint16_t numRows; /**< number of rows in the data table. */ uint16_t numCols; /**< number of columns in the data table. */ q31_t *pData; /**< points to the data table. */ } arm_bilinear_interp_instance_q31; /** * @brief Instance structure for the Q15 bilinear interpolation function. */ typedef struct { uint16_t numRows; /**< number of rows in the data table. */ uint16_t numCols; /**< number of columns in the data table. */ q15_t *pData; /**< points to the data table. */ } arm_bilinear_interp_instance_q15; /** * @brief Instance structure for the Q15 bilinear interpolation function. */ typedef struct { uint16_t numRows; /**< number of rows in the data table. */ uint16_t numCols; /**< number of columns in the data table. */ q7_t *pData; /**< points to the data table. */ } arm_bilinear_interp_instance_q7; /** * @brief Q7 vector multiplication. * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in each vector * @return none. */ void arm_mult_q7( q7_t * pSrcA, q7_t * pSrcB, q7_t * pDst, uint32_t blockSize); /** * @brief Q15 vector multiplication. * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in each vector * @return none. */ void arm_mult_q15( q15_t * pSrcA, q15_t * pSrcB, q15_t * pDst, uint32_t blockSize); /** * @brief Q31 vector multiplication. * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in each vector * @return none. */ void arm_mult_q31( q31_t * pSrcA, q31_t * pSrcB, q31_t * pDst, uint32_t blockSize); /** * @brief Floating-point vector multiplication. * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in each vector * @return none. */ void arm_mult_f32( float32_t * pSrcA, float32_t * pSrcB, float32_t * pDst, uint32_t blockSize); /** * @brief Instance structure for the Q15 CFFT/CIFFT function. */ typedef struct { uint16_t fftLen; /**< length of the FFT. */ uint8_t ifftFlag; /**< flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. */ uint8_t bitReverseFlag; /**< flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. */ q15_t *pTwiddle; /**< points to the Sin twiddle factor table. */ uint16_t *pBitRevTable; /**< points to the bit reversal table. */ uint16_t twidCoefModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ } arm_cfft_radix2_instance_q15; /* Deprecated */ arm_status arm_cfft_radix2_init_q15( arm_cfft_radix2_instance_q15 * S, uint16_t fftLen, uint8_t ifftFlag, uint8_t bitReverseFlag); /* Deprecated */ void arm_cfft_radix2_q15( const arm_cfft_radix2_instance_q15 * S, q15_t * pSrc); /** * @brief Instance structure for the Q15 CFFT/CIFFT function. */ typedef struct { uint16_t fftLen; /**< length of the FFT. */ uint8_t ifftFlag; /**< flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. */ uint8_t bitReverseFlag; /**< flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. */ q15_t *pTwiddle; /**< points to the twiddle factor table. */ uint16_t *pBitRevTable; /**< points to the bit reversal table. */ uint16_t twidCoefModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ } arm_cfft_radix4_instance_q15; /* Deprecated */ arm_status arm_cfft_radix4_init_q15( arm_cfft_radix4_instance_q15 * S, uint16_t fftLen, uint8_t ifftFlag, uint8_t bitReverseFlag); /* Deprecated */ void arm_cfft_radix4_q15( const arm_cfft_radix4_instance_q15 * S, q15_t * pSrc); /** * @brief Instance structure for the Radix-2 Q31 CFFT/CIFFT function. */ typedef struct { uint16_t fftLen; /**< length of the FFT. */ uint8_t ifftFlag; /**< flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. */ uint8_t bitReverseFlag; /**< flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. */ q31_t *pTwiddle; /**< points to the Twiddle factor table. */ uint16_t *pBitRevTable; /**< points to the bit reversal table. */ uint16_t twidCoefModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ } arm_cfft_radix2_instance_q31; /* Deprecated */ arm_status arm_cfft_radix2_init_q31( arm_cfft_radix2_instance_q31 * S, uint16_t fftLen, uint8_t ifftFlag, uint8_t bitReverseFlag); /* Deprecated */ void arm_cfft_radix2_q31( const arm_cfft_radix2_instance_q31 * S, q31_t * pSrc); /** * @brief Instance structure for the Q31 CFFT/CIFFT function. */ typedef struct { uint16_t fftLen; /**< length of the FFT. */ uint8_t ifftFlag; /**< flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. */ uint8_t bitReverseFlag; /**< flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. */ q31_t *pTwiddle; /**< points to the twiddle factor table. */ uint16_t *pBitRevTable; /**< points to the bit reversal table. */ uint16_t twidCoefModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ } arm_cfft_radix4_instance_q31; /* Deprecated */ void arm_cfft_radix4_q31( const arm_cfft_radix4_instance_q31 * S, q31_t * pSrc); /* Deprecated */ arm_status arm_cfft_radix4_init_q31( arm_cfft_radix4_instance_q31 * S, uint16_t fftLen, uint8_t ifftFlag, uint8_t bitReverseFlag); /** * @brief Instance structure for the floating-point CFFT/CIFFT function. */ typedef struct { uint16_t fftLen; /**< length of the FFT. */ uint8_t ifftFlag; /**< flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. */ uint8_t bitReverseFlag; /**< flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. */ float32_t *pTwiddle; /**< points to the Twiddle factor table. */ uint16_t *pBitRevTable; /**< points to the bit reversal table. */ uint16_t twidCoefModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ float32_t onebyfftLen; /**< value of 1/fftLen. */ } arm_cfft_radix2_instance_f32; /* Deprecated */ arm_status arm_cfft_radix2_init_f32( arm_cfft_radix2_instance_f32 * S, uint16_t fftLen, uint8_t ifftFlag, uint8_t bitReverseFlag); /* Deprecated */ void arm_cfft_radix2_f32( const arm_cfft_radix2_instance_f32 * S, float32_t * pSrc); /** * @brief Instance structure for the floating-point CFFT/CIFFT function. */ typedef struct { uint16_t fftLen; /**< length of the FFT. */ uint8_t ifftFlag; /**< flag that selects forward (ifftFlag=0) or inverse (ifftFlag=1) transform. */ uint8_t bitReverseFlag; /**< flag that enables (bitReverseFlag=1) or disables (bitReverseFlag=0) bit reversal of output. */ float32_t *pTwiddle; /**< points to the Twiddle factor table. */ uint16_t *pBitRevTable; /**< points to the bit reversal table. */ uint16_t twidCoefModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ uint16_t bitRevFactor; /**< bit reversal modifier that supports different size FFTs with the same bit reversal table. */ float32_t onebyfftLen; /**< value of 1/fftLen. */ } arm_cfft_radix4_instance_f32; /* Deprecated */ arm_status arm_cfft_radix4_init_f32( arm_cfft_radix4_instance_f32 * S, uint16_t fftLen, uint8_t ifftFlag, uint8_t bitReverseFlag); /* Deprecated */ void arm_cfft_radix4_f32( const arm_cfft_radix4_instance_f32 * S, float32_t * pSrc); /** * @brief Instance structure for the fixed-point CFFT/CIFFT function. */ typedef struct { uint16_t fftLen; /**< length of the FFT. */ const q15_t *pTwiddle; /**< points to the Twiddle factor table. */ const uint16_t *pBitRevTable; /**< points to the bit reversal table. */ uint16_t bitRevLength; /**< bit reversal table length. */ } arm_cfft_instance_q15; void arm_cfft_q15( const arm_cfft_instance_q15 * S, q15_t * p1, uint8_t ifftFlag, uint8_t bitReverseFlag); /** * @brief Instance structure for the fixed-point CFFT/CIFFT function. */ typedef struct { uint16_t fftLen; /**< length of the FFT. */ const q31_t *pTwiddle; /**< points to the Twiddle factor table. */ const uint16_t *pBitRevTable; /**< points to the bit reversal table. */ uint16_t bitRevLength; /**< bit reversal table length. */ } arm_cfft_instance_q31; void arm_cfft_q31( const arm_cfft_instance_q31 * S, q31_t * p1, uint8_t ifftFlag, uint8_t bitReverseFlag); /** * @brief Instance structure for the floating-point CFFT/CIFFT function. */ typedef struct { uint16_t fftLen; /**< length of the FFT. */ const float32_t *pTwiddle; /**< points to the Twiddle factor table. */ const uint16_t *pBitRevTable; /**< points to the bit reversal table. */ uint16_t bitRevLength; /**< bit reversal table length. */ } arm_cfft_instance_f32; void arm_cfft_f32( const arm_cfft_instance_f32 * S, float32_t * p1, uint8_t ifftFlag, uint8_t bitReverseFlag); /** * @brief Instance structure for the Q15 RFFT/RIFFT function. */ typedef struct { uint32_t fftLenReal; /**< length of the real FFT. */ uint8_t ifftFlagR; /**< flag that selects forward (ifftFlagR=0) or inverse (ifftFlagR=1) transform. */ uint8_t bitReverseFlagR; /**< flag that enables (bitReverseFlagR=1) or disables (bitReverseFlagR=0) bit reversal of output. */ uint32_t twidCoefRModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ q15_t *pTwiddleAReal; /**< points to the real twiddle factor table. */ q15_t *pTwiddleBReal; /**< points to the imag twiddle factor table. */ const arm_cfft_instance_q15 *pCfft; /**< points to the complex FFT instance. */ } arm_rfft_instance_q15; arm_status arm_rfft_init_q15( arm_rfft_instance_q15 * S, uint32_t fftLenReal, uint32_t ifftFlagR, uint32_t bitReverseFlag); void arm_rfft_q15( const arm_rfft_instance_q15 * S, q15_t * pSrc, q15_t * pDst); /** * @brief Instance structure for the Q31 RFFT/RIFFT function. */ typedef struct { uint32_t fftLenReal; /**< length of the real FFT. */ uint8_t ifftFlagR; /**< flag that selects forward (ifftFlagR=0) or inverse (ifftFlagR=1) transform. */ uint8_t bitReverseFlagR; /**< flag that enables (bitReverseFlagR=1) or disables (bitReverseFlagR=0) bit reversal of output. */ uint32_t twidCoefRModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ q31_t *pTwiddleAReal; /**< points to the real twiddle factor table. */ q31_t *pTwiddleBReal; /**< points to the imag twiddle factor table. */ const arm_cfft_instance_q31 *pCfft; /**< points to the complex FFT instance. */ } arm_rfft_instance_q31; arm_status arm_rfft_init_q31( arm_rfft_instance_q31 * S, uint32_t fftLenReal, uint32_t ifftFlagR, uint32_t bitReverseFlag); void arm_rfft_q31( const arm_rfft_instance_q31 * S, q31_t * pSrc, q31_t * pDst); /** * @brief Instance structure for the floating-point RFFT/RIFFT function. */ typedef struct { uint32_t fftLenReal; /**< length of the real FFT. */ uint16_t fftLenBy2; /**< length of the complex FFT. */ uint8_t ifftFlagR; /**< flag that selects forward (ifftFlagR=0) or inverse (ifftFlagR=1) transform. */ uint8_t bitReverseFlagR; /**< flag that enables (bitReverseFlagR=1) or disables (bitReverseFlagR=0) bit reversal of output. */ uint32_t twidCoefRModifier; /**< twiddle coefficient modifier that supports different size FFTs with the same twiddle factor table. */ float32_t *pTwiddleAReal; /**< points to the real twiddle factor table. */ float32_t *pTwiddleBReal; /**< points to the imag twiddle factor table. */ arm_cfft_radix4_instance_f32 *pCfft; /**< points to the complex FFT instance. */ } arm_rfft_instance_f32; arm_status arm_rfft_init_f32( arm_rfft_instance_f32 * S, arm_cfft_radix4_instance_f32 * S_CFFT, uint32_t fftLenReal, uint32_t ifftFlagR, uint32_t bitReverseFlag); void arm_rfft_f32( const arm_rfft_instance_f32 * S, float32_t * pSrc, float32_t * pDst); /** * @brief Instance structure for the floating-point RFFT/RIFFT function. */ typedef struct { arm_cfft_instance_f32 Sint; /**< Internal CFFT structure. */ uint16_t fftLenRFFT; /**< length of the real sequence */ float32_t * pTwiddleRFFT; /**< Twiddle factors real stage */ } arm_rfft_fast_instance_f32 ; arm_status arm_rfft_fast_init_f32 ( arm_rfft_fast_instance_f32 * S, uint16_t fftLen); void arm_rfft_fast_f32( arm_rfft_fast_instance_f32 * S, float32_t * p, float32_t * pOut, uint8_t ifftFlag); /** * @brief Instance structure for the floating-point DCT4/IDCT4 function. */ typedef struct { uint16_t N; /**< length of the DCT4. */ uint16_t Nby2; /**< half of the length of the DCT4. */ float32_t normalize; /**< normalizing factor. */ float32_t *pTwiddle; /**< points to the twiddle factor table. */ float32_t *pCosFactor; /**< points to the cosFactor table. */ arm_rfft_instance_f32 *pRfft; /**< points to the real FFT instance. */ arm_cfft_radix4_instance_f32 *pCfft; /**< points to the complex FFT instance. */ } arm_dct4_instance_f32; /** * @brief Initialization function for the floating-point DCT4/IDCT4. * @param[in,out] *S points to an instance of floating-point DCT4/IDCT4 structure. * @param[in] *S_RFFT points to an instance of floating-point RFFT/RIFFT structure. * @param[in] *S_CFFT points to an instance of floating-point CFFT/CIFFT structure. * @param[in] N length of the DCT4. * @param[in] Nby2 half of the length of the DCT4. * @param[in] normalize normalizing factor. * @return arm_status function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_ARGUMENT_ERROR if <code>fftLenReal</code> is not a supported transform length. */ arm_status arm_dct4_init_f32( arm_dct4_instance_f32 * S, arm_rfft_instance_f32 * S_RFFT, arm_cfft_radix4_instance_f32 * S_CFFT, uint16_t N, uint16_t Nby2, float32_t normalize); /** * @brief Processing function for the floating-point DCT4/IDCT4. * @param[in] *S points to an instance of the floating-point DCT4/IDCT4 structure. * @param[in] *pState points to state buffer. * @param[in,out] *pInlineBuffer points to the in-place input and output buffer. * @return none. */ void arm_dct4_f32( const arm_dct4_instance_f32 * S, float32_t * pState, float32_t * pInlineBuffer); /** * @brief Instance structure for the Q31 DCT4/IDCT4 function. */ typedef struct { uint16_t N; /**< length of the DCT4. */ uint16_t Nby2; /**< half of the length of the DCT4. */ q31_t normalize; /**< normalizing factor. */ q31_t *pTwiddle; /**< points to the twiddle factor table. */ q31_t *pCosFactor; /**< points to the cosFactor table. */ arm_rfft_instance_q31 *pRfft; /**< points to the real FFT instance. */ arm_cfft_radix4_instance_q31 *pCfft; /**< points to the complex FFT instance. */ } arm_dct4_instance_q31; /** * @brief Initialization function for the Q31 DCT4/IDCT4. * @param[in,out] *S points to an instance of Q31 DCT4/IDCT4 structure. * @param[in] *S_RFFT points to an instance of Q31 RFFT/RIFFT structure * @param[in] *S_CFFT points to an instance of Q31 CFFT/CIFFT structure * @param[in] N length of the DCT4. * @param[in] Nby2 half of the length of the DCT4. * @param[in] normalize normalizing factor. * @return arm_status function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_ARGUMENT_ERROR if <code>N</code> is not a supported transform length. */ arm_status arm_dct4_init_q31( arm_dct4_instance_q31 * S, arm_rfft_instance_q31 * S_RFFT, arm_cfft_radix4_instance_q31 * S_CFFT, uint16_t N, uint16_t Nby2, q31_t normalize); /** * @brief Processing function for the Q31 DCT4/IDCT4. * @param[in] *S points to an instance of the Q31 DCT4 structure. * @param[in] *pState points to state buffer. * @param[in,out] *pInlineBuffer points to the in-place input and output buffer. * @return none. */ void arm_dct4_q31( const arm_dct4_instance_q31 * S, q31_t * pState, q31_t * pInlineBuffer); /** * @brief Instance structure for the Q15 DCT4/IDCT4 function. */ typedef struct { uint16_t N; /**< length of the DCT4. */ uint16_t Nby2; /**< half of the length of the DCT4. */ q15_t normalize; /**< normalizing factor. */ q15_t *pTwiddle; /**< points to the twiddle factor table. */ q15_t *pCosFactor; /**< points to the cosFactor table. */ arm_rfft_instance_q15 *pRfft; /**< points to the real FFT instance. */ arm_cfft_radix4_instance_q15 *pCfft; /**< points to the complex FFT instance. */ } arm_dct4_instance_q15; /** * @brief Initialization function for the Q15 DCT4/IDCT4. * @param[in,out] *S points to an instance of Q15 DCT4/IDCT4 structure. * @param[in] *S_RFFT points to an instance of Q15 RFFT/RIFFT structure. * @param[in] *S_CFFT points to an instance of Q15 CFFT/CIFFT structure. * @param[in] N length of the DCT4. * @param[in] Nby2 half of the length of the DCT4. * @param[in] normalize normalizing factor. * @return arm_status function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_ARGUMENT_ERROR if <code>N</code> is not a supported transform length. */ arm_status arm_dct4_init_q15( arm_dct4_instance_q15 * S, arm_rfft_instance_q15 * S_RFFT, arm_cfft_radix4_instance_q15 * S_CFFT, uint16_t N, uint16_t Nby2, q15_t normalize); /** * @brief Processing function for the Q15 DCT4/IDCT4. * @param[in] *S points to an instance of the Q15 DCT4 structure. * @param[in] *pState points to state buffer. * @param[in,out] *pInlineBuffer points to the in-place input and output buffer. * @return none. */ void arm_dct4_q15( const arm_dct4_instance_q15 * S, q15_t * pState, q15_t * pInlineBuffer); /** * @brief Floating-point vector addition. * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in each vector * @return none. */ void arm_add_f32( float32_t * pSrcA, float32_t * pSrcB, float32_t * pDst, uint32_t blockSize); /** * @brief Q7 vector addition. * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in each vector * @return none. */ void arm_add_q7( q7_t * pSrcA, q7_t * pSrcB, q7_t * pDst, uint32_t blockSize); /** * @brief Q15 vector addition. * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in each vector * @return none. */ void arm_add_q15( q15_t * pSrcA, q15_t * pSrcB, q15_t * pDst, uint32_t blockSize); /** * @brief Q31 vector addition. * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in each vector * @return none. */ void arm_add_q31( q31_t * pSrcA, q31_t * pSrcB, q31_t * pDst, uint32_t blockSize); /** * @brief Floating-point vector subtraction. * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in each vector * @return none. */ void arm_sub_f32( float32_t * pSrcA, float32_t * pSrcB, float32_t * pDst, uint32_t blockSize); /** * @brief Q7 vector subtraction. * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in each vector * @return none. */ void arm_sub_q7( q7_t * pSrcA, q7_t * pSrcB, q7_t * pDst, uint32_t blockSize); /** * @brief Q15 vector subtraction. * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in each vector * @return none. */ void arm_sub_q15( q15_t * pSrcA, q15_t * pSrcB, q15_t * pDst, uint32_t blockSize); /** * @brief Q31 vector subtraction. * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in each vector * @return none. */ void arm_sub_q31( q31_t * pSrcA, q31_t * pSrcB, q31_t * pDst, uint32_t blockSize); /** * @brief Multiplies a floating-point vector by a scalar. * @param[in] *pSrc points to the input vector * @param[in] scale scale factor to be applied * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in the vector * @return none. */ void arm_scale_f32( float32_t * pSrc, float32_t scale, float32_t * pDst, uint32_t blockSize); /** * @brief Multiplies a Q7 vector by a scalar. * @param[in] *pSrc points to the input vector * @param[in] scaleFract fractional portion of the scale value * @param[in] shift number of bits to shift the result by * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in the vector * @return none. */ void arm_scale_q7( q7_t * pSrc, q7_t scaleFract, int8_t shift, q7_t * pDst, uint32_t blockSize); /** * @brief Multiplies a Q15 vector by a scalar. * @param[in] *pSrc points to the input vector * @param[in] scaleFract fractional portion of the scale value * @param[in] shift number of bits to shift the result by * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in the vector * @return none. */ void arm_scale_q15( q15_t * pSrc, q15_t scaleFract, int8_t shift, q15_t * pDst, uint32_t blockSize); /** * @brief Multiplies a Q31 vector by a scalar. * @param[in] *pSrc points to the input vector * @param[in] scaleFract fractional portion of the scale value * @param[in] shift number of bits to shift the result by * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in the vector * @return none. */ void arm_scale_q31( q31_t * pSrc, q31_t scaleFract, int8_t shift, q31_t * pDst, uint32_t blockSize); /** * @brief Q7 vector absolute value. * @param[in] *pSrc points to the input buffer * @param[out] *pDst points to the output buffer * @param[in] blockSize number of samples in each vector * @return none. */ void arm_abs_q7( q7_t * pSrc, q7_t * pDst, uint32_t blockSize); /** * @brief Floating-point vector absolute value. * @param[in] *pSrc points to the input buffer * @param[out] *pDst points to the output buffer * @param[in] blockSize number of samples in each vector * @return none. */ void arm_abs_f32( float32_t * pSrc, float32_t * pDst, uint32_t blockSize); /** * @brief Q15 vector absolute value. * @param[in] *pSrc points to the input buffer * @param[out] *pDst points to the output buffer * @param[in] blockSize number of samples in each vector * @return none. */ void arm_abs_q15( q15_t * pSrc, q15_t * pDst, uint32_t blockSize); /** * @brief Q31 vector absolute value. * @param[in] *pSrc points to the input buffer * @param[out] *pDst points to the output buffer * @param[in] blockSize number of samples in each vector * @return none. */ void arm_abs_q31( q31_t * pSrc, q31_t * pDst, uint32_t blockSize); /** * @brief Dot product of floating-point vectors. * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[in] blockSize number of samples in each vector * @param[out] *result output result returned here * @return none. */ void arm_dot_prod_f32( float32_t * pSrcA, float32_t * pSrcB, uint32_t blockSize, float32_t * result); /** * @brief Dot product of Q7 vectors. * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[in] blockSize number of samples in each vector * @param[out] *result output result returned here * @return none. */ void arm_dot_prod_q7( q7_t * pSrcA, q7_t * pSrcB, uint32_t blockSize, q31_t * result); /** * @brief Dot product of Q15 vectors. * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[in] blockSize number of samples in each vector * @param[out] *result output result returned here * @return none. */ void arm_dot_prod_q15( q15_t * pSrcA, q15_t * pSrcB, uint32_t blockSize, q63_t * result); /** * @brief Dot product of Q31 vectors. * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[in] blockSize number of samples in each vector * @param[out] *result output result returned here * @return none. */ void arm_dot_prod_q31( q31_t * pSrcA, q31_t * pSrcB, uint32_t blockSize, q63_t * result); /** * @brief Shifts the elements of a Q7 vector a specified number of bits. * @param[in] *pSrc points to the input vector * @param[in] shiftBits number of bits to shift. A positive value shifts left; a negative value shifts right. * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in the vector * @return none. */ void arm_shift_q7( q7_t * pSrc, int8_t shiftBits, q7_t * pDst, uint32_t blockSize); /** * @brief Shifts the elements of a Q15 vector a specified number of bits. * @param[in] *pSrc points to the input vector * @param[in] shiftBits number of bits to shift. A positive value shifts left; a negative value shifts right. * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in the vector * @return none. */ void arm_shift_q15( q15_t * pSrc, int8_t shiftBits, q15_t * pDst, uint32_t blockSize); /** * @brief Shifts the elements of a Q31 vector a specified number of bits. * @param[in] *pSrc points to the input vector * @param[in] shiftBits number of bits to shift. A positive value shifts left; a negative value shifts right. * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in the vector * @return none. */ void arm_shift_q31( q31_t * pSrc, int8_t shiftBits, q31_t * pDst, uint32_t blockSize); /** * @brief Adds a constant offset to a floating-point vector. * @param[in] *pSrc points to the input vector * @param[in] offset is the offset to be added * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in the vector * @return none. */ void arm_offset_f32( float32_t * pSrc, float32_t offset, float32_t * pDst, uint32_t blockSize); /** * @brief Adds a constant offset to a Q7 vector. * @param[in] *pSrc points to the input vector * @param[in] offset is the offset to be added * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in the vector * @return none. */ void arm_offset_q7( q7_t * pSrc, q7_t offset, q7_t * pDst, uint32_t blockSize); /** * @brief Adds a constant offset to a Q15 vector. * @param[in] *pSrc points to the input vector * @param[in] offset is the offset to be added * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in the vector * @return none. */ void arm_offset_q15( q15_t * pSrc, q15_t offset, q15_t * pDst, uint32_t blockSize); /** * @brief Adds a constant offset to a Q31 vector. * @param[in] *pSrc points to the input vector * @param[in] offset is the offset to be added * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in the vector * @return none. */ void arm_offset_q31( q31_t * pSrc, q31_t offset, q31_t * pDst, uint32_t blockSize); /** * @brief Negates the elements of a floating-point vector. * @param[in] *pSrc points to the input vector * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in the vector * @return none. */ void arm_negate_f32( float32_t * pSrc, float32_t * pDst, uint32_t blockSize); /** * @brief Negates the elements of a Q7 vector. * @param[in] *pSrc points to the input vector * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in the vector * @return none. */ void arm_negate_q7( q7_t * pSrc, q7_t * pDst, uint32_t blockSize); /** * @brief Negates the elements of a Q15 vector. * @param[in] *pSrc points to the input vector * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in the vector * @return none. */ void arm_negate_q15( q15_t * pSrc, q15_t * pDst, uint32_t blockSize); /** * @brief Negates the elements of a Q31 vector. * @param[in] *pSrc points to the input vector * @param[out] *pDst points to the output vector * @param[in] blockSize number of samples in the vector * @return none. */ void arm_negate_q31( q31_t * pSrc, q31_t * pDst, uint32_t blockSize); /** * @brief Copies the elements of a floating-point vector. * @param[in] *pSrc input pointer * @param[out] *pDst output pointer * @param[in] blockSize number of samples to process * @return none. */ void arm_copy_f32( float32_t * pSrc, float32_t * pDst, uint32_t blockSize); /** * @brief Copies the elements of a Q7 vector. * @param[in] *pSrc input pointer * @param[out] *pDst output pointer * @param[in] blockSize number of samples to process * @return none. */ void arm_copy_q7( q7_t * pSrc, q7_t * pDst, uint32_t blockSize); /** * @brief Copies the elements of a Q15 vector. * @param[in] *pSrc input pointer * @param[out] *pDst output pointer * @param[in] blockSize number of samples to process * @return none. */ void arm_copy_q15( q15_t * pSrc, q15_t * pDst, uint32_t blockSize); /** * @brief Copies the elements of a Q31 vector. * @param[in] *pSrc input pointer * @param[out] *pDst output pointer * @param[in] blockSize number of samples to process * @return none. */ void arm_copy_q31( q31_t * pSrc, q31_t * pDst, uint32_t blockSize); /** * @brief Fills a constant value into a floating-point vector. * @param[in] value input value to be filled * @param[out] *pDst output pointer * @param[in] blockSize number of samples to process * @return none. */ void arm_fill_f32( float32_t value, float32_t * pDst, uint32_t blockSize); /** * @brief Fills a constant value into a Q7 vector. * @param[in] value input value to be filled * @param[out] *pDst output pointer * @param[in] blockSize number of samples to process * @return none. */ void arm_fill_q7( q7_t value, q7_t * pDst, uint32_t blockSize); /** * @brief Fills a constant value into a Q15 vector. * @param[in] value input value to be filled * @param[out] *pDst output pointer * @param[in] blockSize number of samples to process * @return none. */ void arm_fill_q15( q15_t value, q15_t * pDst, uint32_t blockSize); /** * @brief Fills a constant value into a Q31 vector. * @param[in] value input value to be filled * @param[out] *pDst output pointer * @param[in] blockSize number of samples to process * @return none. */ void arm_fill_q31( q31_t value, q31_t * pDst, uint32_t blockSize); /** * @brief Convolution of floating-point sequences. * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the location where the output result is written. Length srcALen+srcBLen-1. * @return none. */ void arm_conv_f32( float32_t * pSrcA, uint32_t srcALen, float32_t * pSrcB, uint32_t srcBLen, float32_t * pDst); /** * @brief Convolution of Q15 sequences. * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data Length srcALen+srcBLen-1. * @param[in] *pScratch1 points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. * @param[in] *pScratch2 points to scratch buffer of size min(srcALen, srcBLen). * @return none. */ void arm_conv_opt_q15( q15_t * pSrcA, uint32_t srcALen, q15_t * pSrcB, uint32_t srcBLen, q15_t * pDst, q15_t * pScratch1, q15_t * pScratch2); /** * @brief Convolution of Q15 sequences. * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the location where the output result is written. Length srcALen+srcBLen-1. * @return none. */ void arm_conv_q15( q15_t * pSrcA, uint32_t srcALen, q15_t * pSrcB, uint32_t srcBLen, q15_t * pDst); /** * @brief Convolution of Q15 sequences (fast version) for Cortex-M3 and Cortex-M4 * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data Length srcALen+srcBLen-1. * @return none. */ void arm_conv_fast_q15( q15_t * pSrcA, uint32_t srcALen, q15_t * pSrcB, uint32_t srcBLen, q15_t * pDst); /** * @brief Convolution of Q15 sequences (fast version) for Cortex-M3 and Cortex-M4 * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data Length srcALen+srcBLen-1. * @param[in] *pScratch1 points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. * @param[in] *pScratch2 points to scratch buffer of size min(srcALen, srcBLen). * @return none. */ void arm_conv_fast_opt_q15( q15_t * pSrcA, uint32_t srcALen, q15_t * pSrcB, uint32_t srcBLen, q15_t * pDst, q15_t * pScratch1, q15_t * pScratch2); /** * @brief Convolution of Q31 sequences. * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data Length srcALen+srcBLen-1. * @return none. */ void arm_conv_q31( q31_t * pSrcA, uint32_t srcALen, q31_t * pSrcB, uint32_t srcBLen, q31_t * pDst); /** * @brief Convolution of Q31 sequences (fast version) for Cortex-M3 and Cortex-M4 * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data Length srcALen+srcBLen-1. * @return none. */ void arm_conv_fast_q31( q31_t * pSrcA, uint32_t srcALen, q31_t * pSrcB, uint32_t srcBLen, q31_t * pDst); /** * @brief Convolution of Q7 sequences. * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data Length srcALen+srcBLen-1. * @param[in] *pScratch1 points to scratch buffer(of type q15_t) of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. * @param[in] *pScratch2 points to scratch buffer (of type q15_t) of size min(srcALen, srcBLen). * @return none. */ void arm_conv_opt_q7( q7_t * pSrcA, uint32_t srcALen, q7_t * pSrcB, uint32_t srcBLen, q7_t * pDst, q15_t * pScratch1, q15_t * pScratch2); /** * @brief Convolution of Q7 sequences. * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data Length srcALen+srcBLen-1. * @return none. */ void arm_conv_q7( q7_t * pSrcA, uint32_t srcALen, q7_t * pSrcB, uint32_t srcBLen, q7_t * pDst); /** * @brief Partial convolution of floating-point sequences. * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data * @param[in] firstIndex is the first output sample to start with. * @param[in] numPoints is the number of output points to be computed. * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. */ arm_status arm_conv_partial_f32( float32_t * pSrcA, uint32_t srcALen, float32_t * pSrcB, uint32_t srcBLen, float32_t * pDst, uint32_t firstIndex, uint32_t numPoints); /** * @brief Partial convolution of Q15 sequences. * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data * @param[in] firstIndex is the first output sample to start with. * @param[in] numPoints is the number of output points to be computed. * @param[in] * pScratch1 points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. * @param[in] * pScratch2 points to scratch buffer of size min(srcALen, srcBLen). * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. */ arm_status arm_conv_partial_opt_q15( q15_t * pSrcA, uint32_t srcALen, q15_t * pSrcB, uint32_t srcBLen, q15_t * pDst, uint32_t firstIndex, uint32_t numPoints, q15_t * pScratch1, q15_t * pScratch2); /** * @brief Partial convolution of Q15 sequences. * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data * @param[in] firstIndex is the first output sample to start with. * @param[in] numPoints is the number of output points to be computed. * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. */ arm_status arm_conv_partial_q15( q15_t * pSrcA, uint32_t srcALen, q15_t * pSrcB, uint32_t srcBLen, q15_t * pDst, uint32_t firstIndex, uint32_t numPoints); /** * @brief Partial convolution of Q15 sequences (fast version) for Cortex-M3 and Cortex-M4 * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data * @param[in] firstIndex is the first output sample to start with. * @param[in] numPoints is the number of output points to be computed. * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. */ arm_status arm_conv_partial_fast_q15( q15_t * pSrcA, uint32_t srcALen, q15_t * pSrcB, uint32_t srcBLen, q15_t * pDst, uint32_t firstIndex, uint32_t numPoints); /** * @brief Partial convolution of Q15 sequences (fast version) for Cortex-M3 and Cortex-M4 * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data * @param[in] firstIndex is the first output sample to start with. * @param[in] numPoints is the number of output points to be computed. * @param[in] * pScratch1 points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. * @param[in] * pScratch2 points to scratch buffer of size min(srcALen, srcBLen). * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. */ arm_status arm_conv_partial_fast_opt_q15( q15_t * pSrcA, uint32_t srcALen, q15_t * pSrcB, uint32_t srcBLen, q15_t * pDst, uint32_t firstIndex, uint32_t numPoints, q15_t * pScratch1, q15_t * pScratch2); /** * @brief Partial convolution of Q31 sequences. * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data * @param[in] firstIndex is the first output sample to start with. * @param[in] numPoints is the number of output points to be computed. * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. */ arm_status arm_conv_partial_q31( q31_t * pSrcA, uint32_t srcALen, q31_t * pSrcB, uint32_t srcBLen, q31_t * pDst, uint32_t firstIndex, uint32_t numPoints); /** * @brief Partial convolution of Q31 sequences (fast version) for Cortex-M3 and Cortex-M4 * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data * @param[in] firstIndex is the first output sample to start with. * @param[in] numPoints is the number of output points to be computed. * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. */ arm_status arm_conv_partial_fast_q31( q31_t * pSrcA, uint32_t srcALen, q31_t * pSrcB, uint32_t srcBLen, q31_t * pDst, uint32_t firstIndex, uint32_t numPoints); /** * @brief Partial convolution of Q7 sequences * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data * @param[in] firstIndex is the first output sample to start with. * @param[in] numPoints is the number of output points to be computed. * @param[in] *pScratch1 points to scratch buffer(of type q15_t) of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. * @param[in] *pScratch2 points to scratch buffer (of type q15_t) of size min(srcALen, srcBLen). * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. */ arm_status arm_conv_partial_opt_q7( q7_t * pSrcA, uint32_t srcALen, q7_t * pSrcB, uint32_t srcBLen, q7_t * pDst, uint32_t firstIndex, uint32_t numPoints, q15_t * pScratch1, q15_t * pScratch2); /** * @brief Partial convolution of Q7 sequences. * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data * @param[in] firstIndex is the first output sample to start with. * @param[in] numPoints is the number of output points to be computed. * @return Returns either ARM_MATH_SUCCESS if the function completed correctly or ARM_MATH_ARGUMENT_ERROR if the requested subset is not in the range [0 srcALen+srcBLen-2]. */ arm_status arm_conv_partial_q7( q7_t * pSrcA, uint32_t srcALen, q7_t * pSrcB, uint32_t srcBLen, q7_t * pDst, uint32_t firstIndex, uint32_t numPoints); /** * @brief Instance structure for the Q15 FIR decimator. */ typedef struct { uint8_t M; /**< decimation factor. */ uint16_t numTaps; /**< number of coefficients in the filter. */ q15_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps.*/ q15_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ } arm_fir_decimate_instance_q15; /** * @brief Instance structure for the Q31 FIR decimator. */ typedef struct { uint8_t M; /**< decimation factor. */ uint16_t numTaps; /**< number of coefficients in the filter. */ q31_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps.*/ q31_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ } arm_fir_decimate_instance_q31; /** * @brief Instance structure for the floating-point FIR decimator. */ typedef struct { uint8_t M; /**< decimation factor. */ uint16_t numTaps; /**< number of coefficients in the filter. */ float32_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps.*/ float32_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ } arm_fir_decimate_instance_f32; /** * @brief Processing function for the floating-point FIR decimator. * @param[in] *S points to an instance of the floating-point FIR decimator structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data * @param[in] blockSize number of input samples to process per call. * @return none */ void arm_fir_decimate_f32( const arm_fir_decimate_instance_f32 * S, float32_t * pSrc, float32_t * pDst, uint32_t blockSize); /** * @brief Initialization function for the floating-point FIR decimator. * @param[in,out] *S points to an instance of the floating-point FIR decimator structure. * @param[in] numTaps number of coefficients in the filter. * @param[in] M decimation factor. * @param[in] *pCoeffs points to the filter coefficients. * @param[in] *pState points to the state buffer. * @param[in] blockSize number of input samples to process per call. * @return The function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_LENGTH_ERROR if * <code>blockSize</code> is not a multiple of <code>M</code>. */ arm_status arm_fir_decimate_init_f32( arm_fir_decimate_instance_f32 * S, uint16_t numTaps, uint8_t M, float32_t * pCoeffs, float32_t * pState, uint32_t blockSize); /** * @brief Processing function for the Q15 FIR decimator. * @param[in] *S points to an instance of the Q15 FIR decimator structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data * @param[in] blockSize number of input samples to process per call. * @return none */ void arm_fir_decimate_q15( const arm_fir_decimate_instance_q15 * S, q15_t * pSrc, q15_t * pDst, uint32_t blockSize); /** * @brief Processing function for the Q15 FIR decimator (fast variant) for Cortex-M3 and Cortex-M4. * @param[in] *S points to an instance of the Q15 FIR decimator structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data * @param[in] blockSize number of input samples to process per call. * @return none */ void arm_fir_decimate_fast_q15( const arm_fir_decimate_instance_q15 * S, q15_t * pSrc, q15_t * pDst, uint32_t blockSize); /** * @brief Initialization function for the Q15 FIR decimator. * @param[in,out] *S points to an instance of the Q15 FIR decimator structure. * @param[in] numTaps number of coefficients in the filter. * @param[in] M decimation factor. * @param[in] *pCoeffs points to the filter coefficients. * @param[in] *pState points to the state buffer. * @param[in] blockSize number of input samples to process per call. * @return The function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_LENGTH_ERROR if * <code>blockSize</code> is not a multiple of <code>M</code>. */ arm_status arm_fir_decimate_init_q15( arm_fir_decimate_instance_q15 * S, uint16_t numTaps, uint8_t M, q15_t * pCoeffs, q15_t * pState, uint32_t blockSize); /** * @brief Processing function for the Q31 FIR decimator. * @param[in] *S points to an instance of the Q31 FIR decimator structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data * @param[in] blockSize number of input samples to process per call. * @return none */ void arm_fir_decimate_q31( const arm_fir_decimate_instance_q31 * S, q31_t * pSrc, q31_t * pDst, uint32_t blockSize); /** * @brief Processing function for the Q31 FIR decimator (fast variant) for Cortex-M3 and Cortex-M4. * @param[in] *S points to an instance of the Q31 FIR decimator structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data * @param[in] blockSize number of input samples to process per call. * @return none */ void arm_fir_decimate_fast_q31( arm_fir_decimate_instance_q31 * S, q31_t * pSrc, q31_t * pDst, uint32_t blockSize); /** * @brief Initialization function for the Q31 FIR decimator. * @param[in,out] *S points to an instance of the Q31 FIR decimator structure. * @param[in] numTaps number of coefficients in the filter. * @param[in] M decimation factor. * @param[in] *pCoeffs points to the filter coefficients. * @param[in] *pState points to the state buffer. * @param[in] blockSize number of input samples to process per call. * @return The function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_LENGTH_ERROR if * <code>blockSize</code> is not a multiple of <code>M</code>. */ arm_status arm_fir_decimate_init_q31( arm_fir_decimate_instance_q31 * S, uint16_t numTaps, uint8_t M, q31_t * pCoeffs, q31_t * pState, uint32_t blockSize); /** * @brief Instance structure for the Q15 FIR interpolator. */ typedef struct { uint8_t L; /**< upsample factor. */ uint16_t phaseLength; /**< length of each polyphase filter component. */ q15_t *pCoeffs; /**< points to the coefficient array. The array is of length L*phaseLength. */ q15_t *pState; /**< points to the state variable array. The array is of length blockSize+phaseLength-1. */ } arm_fir_interpolate_instance_q15; /** * @brief Instance structure for the Q31 FIR interpolator. */ typedef struct { uint8_t L; /**< upsample factor. */ uint16_t phaseLength; /**< length of each polyphase filter component. */ q31_t *pCoeffs; /**< points to the coefficient array. The array is of length L*phaseLength. */ q31_t *pState; /**< points to the state variable array. The array is of length blockSize+phaseLength-1. */ } arm_fir_interpolate_instance_q31; /** * @brief Instance structure for the floating-point FIR interpolator. */ typedef struct { uint8_t L; /**< upsample factor. */ uint16_t phaseLength; /**< length of each polyphase filter component. */ float32_t *pCoeffs; /**< points to the coefficient array. The array is of length L*phaseLength. */ float32_t *pState; /**< points to the state variable array. The array is of length phaseLength+numTaps-1. */ } arm_fir_interpolate_instance_f32; /** * @brief Processing function for the Q15 FIR interpolator. * @param[in] *S points to an instance of the Q15 FIR interpolator structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data. * @param[in] blockSize number of input samples to process per call. * @return none. */ void arm_fir_interpolate_q15( const arm_fir_interpolate_instance_q15 * S, q15_t * pSrc, q15_t * pDst, uint32_t blockSize); /** * @brief Initialization function for the Q15 FIR interpolator. * @param[in,out] *S points to an instance of the Q15 FIR interpolator structure. * @param[in] L upsample factor. * @param[in] numTaps number of filter coefficients in the filter. * @param[in] *pCoeffs points to the filter coefficient buffer. * @param[in] *pState points to the state buffer. * @param[in] blockSize number of input samples to process per call. * @return The function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_LENGTH_ERROR if * the filter length <code>numTaps</code> is not a multiple of the interpolation factor <code>L</code>. */ arm_status arm_fir_interpolate_init_q15( arm_fir_interpolate_instance_q15 * S, uint8_t L, uint16_t numTaps, q15_t * pCoeffs, q15_t * pState, uint32_t blockSize); /** * @brief Processing function for the Q31 FIR interpolator. * @param[in] *S points to an instance of the Q15 FIR interpolator structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data. * @param[in] blockSize number of input samples to process per call. * @return none. */ void arm_fir_interpolate_q31( const arm_fir_interpolate_instance_q31 * S, q31_t * pSrc, q31_t * pDst, uint32_t blockSize); /** * @brief Initialization function for the Q31 FIR interpolator. * @param[in,out] *S points to an instance of the Q31 FIR interpolator structure. * @param[in] L upsample factor. * @param[in] numTaps number of filter coefficients in the filter. * @param[in] *pCoeffs points to the filter coefficient buffer. * @param[in] *pState points to the state buffer. * @param[in] blockSize number of input samples to process per call. * @return The function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_LENGTH_ERROR if * the filter length <code>numTaps</code> is not a multiple of the interpolation factor <code>L</code>. */ arm_status arm_fir_interpolate_init_q31( arm_fir_interpolate_instance_q31 * S, uint8_t L, uint16_t numTaps, q31_t * pCoeffs, q31_t * pState, uint32_t blockSize); /** * @brief Processing function for the floating-point FIR interpolator. * @param[in] *S points to an instance of the floating-point FIR interpolator structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data. * @param[in] blockSize number of input samples to process per call. * @return none. */ void arm_fir_interpolate_f32( const arm_fir_interpolate_instance_f32 * S, float32_t * pSrc, float32_t * pDst, uint32_t blockSize); /** * @brief Initialization function for the floating-point FIR interpolator. * @param[in,out] *S points to an instance of the floating-point FIR interpolator structure. * @param[in] L upsample factor. * @param[in] numTaps number of filter coefficients in the filter. * @param[in] *pCoeffs points to the filter coefficient buffer. * @param[in] *pState points to the state buffer. * @param[in] blockSize number of input samples to process per call. * @return The function returns ARM_MATH_SUCCESS if initialization is successful or ARM_MATH_LENGTH_ERROR if * the filter length <code>numTaps</code> is not a multiple of the interpolation factor <code>L</code>. */ arm_status arm_fir_interpolate_init_f32( arm_fir_interpolate_instance_f32 * S, uint8_t L, uint16_t numTaps, float32_t * pCoeffs, float32_t * pState, uint32_t blockSize); /** * @brief Instance structure for the high precision Q31 Biquad cascade filter. */ typedef struct { uint8_t numStages; /**< number of 2nd order stages in the filter. Overall order is 2*numStages. */ q63_t *pState; /**< points to the array of state coefficients. The array is of length 4*numStages. */ q31_t *pCoeffs; /**< points to the array of coefficients. The array is of length 5*numStages. */ uint8_t postShift; /**< additional shift, in bits, applied to each output sample. */ } arm_biquad_cas_df1_32x64_ins_q31; /** * @param[in] *S points to an instance of the high precision Q31 Biquad cascade filter structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data * @param[in] blockSize number of samples to process. * @return none. */ void arm_biquad_cas_df1_32x64_q31( const arm_biquad_cas_df1_32x64_ins_q31 * S, q31_t * pSrc, q31_t * pDst, uint32_t blockSize); /** * @param[in,out] *S points to an instance of the high precision Q31 Biquad cascade filter structure. * @param[in] numStages number of 2nd order stages in the filter. * @param[in] *pCoeffs points to the filter coefficients. * @param[in] *pState points to the state buffer. * @param[in] postShift shift to be applied to the output. Varies according to the coefficients format * @return none */ void arm_biquad_cas_df1_32x64_init_q31( arm_biquad_cas_df1_32x64_ins_q31 * S, uint8_t numStages, q31_t * pCoeffs, q63_t * pState, uint8_t postShift); /** * @brief Instance structure for the floating-point transposed direct form II Biquad cascade filter. */ typedef struct { uint8_t numStages; /**< number of 2nd order stages in the filter. Overall order is 2*numStages. */ float32_t *pState; /**< points to the array of state coefficients. The array is of length 2*numStages. */ float32_t *pCoeffs; /**< points to the array of coefficients. The array is of length 5*numStages. */ } arm_biquad_cascade_df2T_instance_f32; /** * @brief Instance structure for the floating-point transposed direct form II Biquad cascade filter. */ typedef struct { uint8_t numStages; /**< number of 2nd order stages in the filter. Overall order is 2*numStages. */ float32_t *pState; /**< points to the array of state coefficients. The array is of length 4*numStages. */ float32_t *pCoeffs; /**< points to the array of coefficients. The array is of length 5*numStages. */ } arm_biquad_cascade_stereo_df2T_instance_f32; /** * @brief Instance structure for the floating-point transposed direct form II Biquad cascade filter. */ typedef struct { uint8_t numStages; /**< number of 2nd order stages in the filter. Overall order is 2*numStages. */ float64_t *pState; /**< points to the array of state coefficients. The array is of length 2*numStages. */ float64_t *pCoeffs; /**< points to the array of coefficients. The array is of length 5*numStages. */ } arm_biquad_cascade_df2T_instance_f64; /** * @brief Processing function for the floating-point transposed direct form II Biquad cascade filter. * @param[in] *S points to an instance of the filter data structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data * @param[in] blockSize number of samples to process. * @return none. */ void arm_biquad_cascade_df2T_f32( const arm_biquad_cascade_df2T_instance_f32 * S, float32_t * pSrc, float32_t * pDst, uint32_t blockSize); /** * @brief Processing function for the floating-point transposed direct form II Biquad cascade filter. 2 channels * @param[in] *S points to an instance of the filter data structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data * @param[in] blockSize number of samples to process. * @return none. */ void arm_biquad_cascade_stereo_df2T_f32( const arm_biquad_cascade_stereo_df2T_instance_f32 * S, float32_t * pSrc, float32_t * pDst, uint32_t blockSize); /** * @brief Processing function for the floating-point transposed direct form II Biquad cascade filter. * @param[in] *S points to an instance of the filter data structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data * @param[in] blockSize number of samples to process. * @return none. */ void arm_biquad_cascade_df2T_f64( const arm_biquad_cascade_df2T_instance_f64 * S, float64_t * pSrc, float64_t * pDst, uint32_t blockSize); /** * @brief Initialization function for the floating-point transposed direct form II Biquad cascade filter. * @param[in,out] *S points to an instance of the filter data structure. * @param[in] numStages number of 2nd order stages in the filter. * @param[in] *pCoeffs points to the filter coefficients. * @param[in] *pState points to the state buffer. * @return none */ void arm_biquad_cascade_df2T_init_f32( arm_biquad_cascade_df2T_instance_f32 * S, uint8_t numStages, float32_t * pCoeffs, float32_t * pState); /** * @brief Initialization function for the floating-point transposed direct form II Biquad cascade filter. * @param[in,out] *S points to an instance of the filter data structure. * @param[in] numStages number of 2nd order stages in the filter. * @param[in] *pCoeffs points to the filter coefficients. * @param[in] *pState points to the state buffer. * @return none */ void arm_biquad_cascade_stereo_df2T_init_f32( arm_biquad_cascade_stereo_df2T_instance_f32 * S, uint8_t numStages, float32_t * pCoeffs, float32_t * pState); /** * @brief Initialization function for the floating-point transposed direct form II Biquad cascade filter. * @param[in,out] *S points to an instance of the filter data structure. * @param[in] numStages number of 2nd order stages in the filter. * @param[in] *pCoeffs points to the filter coefficients. * @param[in] *pState points to the state buffer. * @return none */ void arm_biquad_cascade_df2T_init_f64( arm_biquad_cascade_df2T_instance_f64 * S, uint8_t numStages, float64_t * pCoeffs, float64_t * pState); /** * @brief Instance structure for the Q15 FIR lattice filter. */ typedef struct { uint16_t numStages; /**< number of filter stages. */ q15_t *pState; /**< points to the state variable array. The array is of length numStages. */ q15_t *pCoeffs; /**< points to the coefficient array. The array is of length numStages. */ } arm_fir_lattice_instance_q15; /** * @brief Instance structure for the Q31 FIR lattice filter. */ typedef struct { uint16_t numStages; /**< number of filter stages. */ q31_t *pState; /**< points to the state variable array. The array is of length numStages. */ q31_t *pCoeffs; /**< points to the coefficient array. The array is of length numStages. */ } arm_fir_lattice_instance_q31; /** * @brief Instance structure for the floating-point FIR lattice filter. */ typedef struct { uint16_t numStages; /**< number of filter stages. */ float32_t *pState; /**< points to the state variable array. The array is of length numStages. */ float32_t *pCoeffs; /**< points to the coefficient array. The array is of length numStages. */ } arm_fir_lattice_instance_f32; /** * @brief Initialization function for the Q15 FIR lattice filter. * @param[in] *S points to an instance of the Q15 FIR lattice structure. * @param[in] numStages number of filter stages. * @param[in] *pCoeffs points to the coefficient buffer. The array is of length numStages. * @param[in] *pState points to the state buffer. The array is of length numStages. * @return none. */ void arm_fir_lattice_init_q15( arm_fir_lattice_instance_q15 * S, uint16_t numStages, q15_t * pCoeffs, q15_t * pState); /** * @brief Processing function for the Q15 FIR lattice filter. * @param[in] *S points to an instance of the Q15 FIR lattice structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_fir_lattice_q15( const arm_fir_lattice_instance_q15 * S, q15_t * pSrc, q15_t * pDst, uint32_t blockSize); /** * @brief Initialization function for the Q31 FIR lattice filter. * @param[in] *S points to an instance of the Q31 FIR lattice structure. * @param[in] numStages number of filter stages. * @param[in] *pCoeffs points to the coefficient buffer. The array is of length numStages. * @param[in] *pState points to the state buffer. The array is of length numStages. * @return none. */ void arm_fir_lattice_init_q31( arm_fir_lattice_instance_q31 * S, uint16_t numStages, q31_t * pCoeffs, q31_t * pState); /** * @brief Processing function for the Q31 FIR lattice filter. * @param[in] *S points to an instance of the Q31 FIR lattice structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data * @param[in] blockSize number of samples to process. * @return none. */ void arm_fir_lattice_q31( const arm_fir_lattice_instance_q31 * S, q31_t * pSrc, q31_t * pDst, uint32_t blockSize); /** * @brief Initialization function for the floating-point FIR lattice filter. * @param[in] *S points to an instance of the floating-point FIR lattice structure. * @param[in] numStages number of filter stages. * @param[in] *pCoeffs points to the coefficient buffer. The array is of length numStages. * @param[in] *pState points to the state buffer. The array is of length numStages. * @return none. */ void arm_fir_lattice_init_f32( arm_fir_lattice_instance_f32 * S, uint16_t numStages, float32_t * pCoeffs, float32_t * pState); /** * @brief Processing function for the floating-point FIR lattice filter. * @param[in] *S points to an instance of the floating-point FIR lattice structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data * @param[in] blockSize number of samples to process. * @return none. */ void arm_fir_lattice_f32( const arm_fir_lattice_instance_f32 * S, float32_t * pSrc, float32_t * pDst, uint32_t blockSize); /** * @brief Instance structure for the Q15 IIR lattice filter. */ typedef struct { uint16_t numStages; /**< number of stages in the filter. */ q15_t *pState; /**< points to the state variable array. The array is of length numStages+blockSize. */ q15_t *pkCoeffs; /**< points to the reflection coefficient array. The array is of length numStages. */ q15_t *pvCoeffs; /**< points to the ladder coefficient array. The array is of length numStages+1. */ } arm_iir_lattice_instance_q15; /** * @brief Instance structure for the Q31 IIR lattice filter. */ typedef struct { uint16_t numStages; /**< number of stages in the filter. */ q31_t *pState; /**< points to the state variable array. The array is of length numStages+blockSize. */ q31_t *pkCoeffs; /**< points to the reflection coefficient array. The array is of length numStages. */ q31_t *pvCoeffs; /**< points to the ladder coefficient array. The array is of length numStages+1. */ } arm_iir_lattice_instance_q31; /** * @brief Instance structure for the floating-point IIR lattice filter. */ typedef struct { uint16_t numStages; /**< number of stages in the filter. */ float32_t *pState; /**< points to the state variable array. The array is of length numStages+blockSize. */ float32_t *pkCoeffs; /**< points to the reflection coefficient array. The array is of length numStages. */ float32_t *pvCoeffs; /**< points to the ladder coefficient array. The array is of length numStages+1. */ } arm_iir_lattice_instance_f32; /** * @brief Processing function for the floating-point IIR lattice filter. * @param[in] *S points to an instance of the floating-point IIR lattice structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_iir_lattice_f32( const arm_iir_lattice_instance_f32 * S, float32_t * pSrc, float32_t * pDst, uint32_t blockSize); /** * @brief Initialization function for the floating-point IIR lattice filter. * @param[in] *S points to an instance of the floating-point IIR lattice structure. * @param[in] numStages number of stages in the filter. * @param[in] *pkCoeffs points to the reflection coefficient buffer. The array is of length numStages. * @param[in] *pvCoeffs points to the ladder coefficient buffer. The array is of length numStages+1. * @param[in] *pState points to the state buffer. The array is of length numStages+blockSize-1. * @param[in] blockSize number of samples to process. * @return none. */ void arm_iir_lattice_init_f32( arm_iir_lattice_instance_f32 * S, uint16_t numStages, float32_t * pkCoeffs, float32_t * pvCoeffs, float32_t * pState, uint32_t blockSize); /** * @brief Processing function for the Q31 IIR lattice filter. * @param[in] *S points to an instance of the Q31 IIR lattice structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_iir_lattice_q31( const arm_iir_lattice_instance_q31 * S, q31_t * pSrc, q31_t * pDst, uint32_t blockSize); /** * @brief Initialization function for the Q31 IIR lattice filter. * @param[in] *S points to an instance of the Q31 IIR lattice structure. * @param[in] numStages number of stages in the filter. * @param[in] *pkCoeffs points to the reflection coefficient buffer. The array is of length numStages. * @param[in] *pvCoeffs points to the ladder coefficient buffer. The array is of length numStages+1. * @param[in] *pState points to the state buffer. The array is of length numStages+blockSize. * @param[in] blockSize number of samples to process. * @return none. */ void arm_iir_lattice_init_q31( arm_iir_lattice_instance_q31 * S, uint16_t numStages, q31_t * pkCoeffs, q31_t * pvCoeffs, q31_t * pState, uint32_t blockSize); /** * @brief Processing function for the Q15 IIR lattice filter. * @param[in] *S points to an instance of the Q15 IIR lattice structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_iir_lattice_q15( const arm_iir_lattice_instance_q15 * S, q15_t * pSrc, q15_t * pDst, uint32_t blockSize); /** * @brief Initialization function for the Q15 IIR lattice filter. * @param[in] *S points to an instance of the fixed-point Q15 IIR lattice structure. * @param[in] numStages number of stages in the filter. * @param[in] *pkCoeffs points to reflection coefficient buffer. The array is of length numStages. * @param[in] *pvCoeffs points to ladder coefficient buffer. The array is of length numStages+1. * @param[in] *pState points to state buffer. The array is of length numStages+blockSize. * @param[in] blockSize number of samples to process per call. * @return none. */ void arm_iir_lattice_init_q15( arm_iir_lattice_instance_q15 * S, uint16_t numStages, q15_t * pkCoeffs, q15_t * pvCoeffs, q15_t * pState, uint32_t blockSize); /** * @brief Instance structure for the floating-point LMS filter. */ typedef struct { uint16_t numTaps; /**< number of coefficients in the filter. */ float32_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ float32_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps. */ float32_t mu; /**< step size that controls filter coefficient updates. */ } arm_lms_instance_f32; /** * @brief Processing function for floating-point LMS filter. * @param[in] *S points to an instance of the floating-point LMS filter structure. * @param[in] *pSrc points to the block of input data. * @param[in] *pRef points to the block of reference data. * @param[out] *pOut points to the block of output data. * @param[out] *pErr points to the block of error data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_lms_f32( const arm_lms_instance_f32 * S, float32_t * pSrc, float32_t * pRef, float32_t * pOut, float32_t * pErr, uint32_t blockSize); /** * @brief Initialization function for floating-point LMS filter. * @param[in] *S points to an instance of the floating-point LMS filter structure. * @param[in] numTaps number of filter coefficients. * @param[in] *pCoeffs points to the coefficient buffer. * @param[in] *pState points to state buffer. * @param[in] mu step size that controls filter coefficient updates. * @param[in] blockSize number of samples to process. * @return none. */ void arm_lms_init_f32( arm_lms_instance_f32 * S, uint16_t numTaps, float32_t * pCoeffs, float32_t * pState, float32_t mu, uint32_t blockSize); /** * @brief Instance structure for the Q15 LMS filter. */ typedef struct { uint16_t numTaps; /**< number of coefficients in the filter. */ q15_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ q15_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps. */ q15_t mu; /**< step size that controls filter coefficient updates. */ uint32_t postShift; /**< bit shift applied to coefficients. */ } arm_lms_instance_q15; /** * @brief Initialization function for the Q15 LMS filter. * @param[in] *S points to an instance of the Q15 LMS filter structure. * @param[in] numTaps number of filter coefficients. * @param[in] *pCoeffs points to the coefficient buffer. * @param[in] *pState points to the state buffer. * @param[in] mu step size that controls filter coefficient updates. * @param[in] blockSize number of samples to process. * @param[in] postShift bit shift applied to coefficients. * @return none. */ void arm_lms_init_q15( arm_lms_instance_q15 * S, uint16_t numTaps, q15_t * pCoeffs, q15_t * pState, q15_t mu, uint32_t blockSize, uint32_t postShift); /** * @brief Processing function for Q15 LMS filter. * @param[in] *S points to an instance of the Q15 LMS filter structure. * @param[in] *pSrc points to the block of input data. * @param[in] *pRef points to the block of reference data. * @param[out] *pOut points to the block of output data. * @param[out] *pErr points to the block of error data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_lms_q15( const arm_lms_instance_q15 * S, q15_t * pSrc, q15_t * pRef, q15_t * pOut, q15_t * pErr, uint32_t blockSize); /** * @brief Instance structure for the Q31 LMS filter. */ typedef struct { uint16_t numTaps; /**< number of coefficients in the filter. */ q31_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ q31_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps. */ q31_t mu; /**< step size that controls filter coefficient updates. */ uint32_t postShift; /**< bit shift applied to coefficients. */ } arm_lms_instance_q31; /** * @brief Processing function for Q31 LMS filter. * @param[in] *S points to an instance of the Q15 LMS filter structure. * @param[in] *pSrc points to the block of input data. * @param[in] *pRef points to the block of reference data. * @param[out] *pOut points to the block of output data. * @param[out] *pErr points to the block of error data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_lms_q31( const arm_lms_instance_q31 * S, q31_t * pSrc, q31_t * pRef, q31_t * pOut, q31_t * pErr, uint32_t blockSize); /** * @brief Initialization function for Q31 LMS filter. * @param[in] *S points to an instance of the Q31 LMS filter structure. * @param[in] numTaps number of filter coefficients. * @param[in] *pCoeffs points to coefficient buffer. * @param[in] *pState points to state buffer. * @param[in] mu step size that controls filter coefficient updates. * @param[in] blockSize number of samples to process. * @param[in] postShift bit shift applied to coefficients. * @return none. */ void arm_lms_init_q31( arm_lms_instance_q31 * S, uint16_t numTaps, q31_t * pCoeffs, q31_t * pState, q31_t mu, uint32_t blockSize, uint32_t postShift); /** * @brief Instance structure for the floating-point normalized LMS filter. */ typedef struct { uint16_t numTaps; /**< number of coefficients in the filter. */ float32_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ float32_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps. */ float32_t mu; /**< step size that control filter coefficient updates. */ float32_t energy; /**< saves previous frame energy. */ float32_t x0; /**< saves previous input sample. */ } arm_lms_norm_instance_f32; /** * @brief Processing function for floating-point normalized LMS filter. * @param[in] *S points to an instance of the floating-point normalized LMS filter structure. * @param[in] *pSrc points to the block of input data. * @param[in] *pRef points to the block of reference data. * @param[out] *pOut points to the block of output data. * @param[out] *pErr points to the block of error data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_lms_norm_f32( arm_lms_norm_instance_f32 * S, float32_t * pSrc, float32_t * pRef, float32_t * pOut, float32_t * pErr, uint32_t blockSize); /** * @brief Initialization function for floating-point normalized LMS filter. * @param[in] *S points to an instance of the floating-point LMS filter structure. * @param[in] numTaps number of filter coefficients. * @param[in] *pCoeffs points to coefficient buffer. * @param[in] *pState points to state buffer. * @param[in] mu step size that controls filter coefficient updates. * @param[in] blockSize number of samples to process. * @return none. */ void arm_lms_norm_init_f32( arm_lms_norm_instance_f32 * S, uint16_t numTaps, float32_t * pCoeffs, float32_t * pState, float32_t mu, uint32_t blockSize); /** * @brief Instance structure for the Q31 normalized LMS filter. */ typedef struct { uint16_t numTaps; /**< number of coefficients in the filter. */ q31_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ q31_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps. */ q31_t mu; /**< step size that controls filter coefficient updates. */ uint8_t postShift; /**< bit shift applied to coefficients. */ q31_t *recipTable; /**< points to the reciprocal initial value table. */ q31_t energy; /**< saves previous frame energy. */ q31_t x0; /**< saves previous input sample. */ } arm_lms_norm_instance_q31; /** * @brief Processing function for Q31 normalized LMS filter. * @param[in] *S points to an instance of the Q31 normalized LMS filter structure. * @param[in] *pSrc points to the block of input data. * @param[in] *pRef points to the block of reference data. * @param[out] *pOut points to the block of output data. * @param[out] *pErr points to the block of error data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_lms_norm_q31( arm_lms_norm_instance_q31 * S, q31_t * pSrc, q31_t * pRef, q31_t * pOut, q31_t * pErr, uint32_t blockSize); /** * @brief Initialization function for Q31 normalized LMS filter. * @param[in] *S points to an instance of the Q31 normalized LMS filter structure. * @param[in] numTaps number of filter coefficients. * @param[in] *pCoeffs points to coefficient buffer. * @param[in] *pState points to state buffer. * @param[in] mu step size that controls filter coefficient updates. * @param[in] blockSize number of samples to process. * @param[in] postShift bit shift applied to coefficients. * @return none. */ void arm_lms_norm_init_q31( arm_lms_norm_instance_q31 * S, uint16_t numTaps, q31_t * pCoeffs, q31_t * pState, q31_t mu, uint32_t blockSize, uint8_t postShift); /** * @brief Instance structure for the Q15 normalized LMS filter. */ typedef struct { uint16_t numTaps; /**< Number of coefficients in the filter. */ q15_t *pState; /**< points to the state variable array. The array is of length numTaps+blockSize-1. */ q15_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps. */ q15_t mu; /**< step size that controls filter coefficient updates. */ uint8_t postShift; /**< bit shift applied to coefficients. */ q15_t *recipTable; /**< Points to the reciprocal initial value table. */ q15_t energy; /**< saves previous frame energy. */ q15_t x0; /**< saves previous input sample. */ } arm_lms_norm_instance_q15; /** * @brief Processing function for Q15 normalized LMS filter. * @param[in] *S points to an instance of the Q15 normalized LMS filter structure. * @param[in] *pSrc points to the block of input data. * @param[in] *pRef points to the block of reference data. * @param[out] *pOut points to the block of output data. * @param[out] *pErr points to the block of error data. * @param[in] blockSize number of samples to process. * @return none. */ void arm_lms_norm_q15( arm_lms_norm_instance_q15 * S, q15_t * pSrc, q15_t * pRef, q15_t * pOut, q15_t * pErr, uint32_t blockSize); /** * @brief Initialization function for Q15 normalized LMS filter. * @param[in] *S points to an instance of the Q15 normalized LMS filter structure. * @param[in] numTaps number of filter coefficients. * @param[in] *pCoeffs points to coefficient buffer. * @param[in] *pState points to state buffer. * @param[in] mu step size that controls filter coefficient updates. * @param[in] blockSize number of samples to process. * @param[in] postShift bit shift applied to coefficients. * @return none. */ void arm_lms_norm_init_q15( arm_lms_norm_instance_q15 * S, uint16_t numTaps, q15_t * pCoeffs, q15_t * pState, q15_t mu, uint32_t blockSize, uint8_t postShift); /** * @brief Correlation of floating-point sequences. * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. * @return none. */ void arm_correlate_f32( float32_t * pSrcA, uint32_t srcALen, float32_t * pSrcB, uint32_t srcBLen, float32_t * pDst); /** * @brief Correlation of Q15 sequences * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. * @param[in] *pScratch points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. * @return none. */ void arm_correlate_opt_q15( q15_t * pSrcA, uint32_t srcALen, q15_t * pSrcB, uint32_t srcBLen, q15_t * pDst, q15_t * pScratch); /** * @brief Correlation of Q15 sequences. * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. * @return none. */ void arm_correlate_q15( q15_t * pSrcA, uint32_t srcALen, q15_t * pSrcB, uint32_t srcBLen, q15_t * pDst); /** * @brief Correlation of Q15 sequences (fast version) for Cortex-M3 and Cortex-M4. * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. * @return none. */ void arm_correlate_fast_q15( q15_t * pSrcA, uint32_t srcALen, q15_t * pSrcB, uint32_t srcBLen, q15_t * pDst); /** * @brief Correlation of Q15 sequences (fast version) for Cortex-M3 and Cortex-M4. * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. * @param[in] *pScratch points to scratch buffer of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. * @return none. */ void arm_correlate_fast_opt_q15( q15_t * pSrcA, uint32_t srcALen, q15_t * pSrcB, uint32_t srcBLen, q15_t * pDst, q15_t * pScratch); /** * @brief Correlation of Q31 sequences. * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. * @return none. */ void arm_correlate_q31( q31_t * pSrcA, uint32_t srcALen, q31_t * pSrcB, uint32_t srcBLen, q31_t * pDst); /** * @brief Correlation of Q31 sequences (fast version) for Cortex-M3 and Cortex-M4 * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. * @return none. */ void arm_correlate_fast_q31( q31_t * pSrcA, uint32_t srcALen, q31_t * pSrcB, uint32_t srcBLen, q31_t * pDst); /** * @brief Correlation of Q7 sequences. * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. * @param[in] *pScratch1 points to scratch buffer(of type q15_t) of size max(srcALen, srcBLen) + 2*min(srcALen, srcBLen) - 2. * @param[in] *pScratch2 points to scratch buffer (of type q15_t) of size min(srcALen, srcBLen). * @return none. */ void arm_correlate_opt_q7( q7_t * pSrcA, uint32_t srcALen, q7_t * pSrcB, uint32_t srcBLen, q7_t * pDst, q15_t * pScratch1, q15_t * pScratch2); /** * @brief Correlation of Q7 sequences. * @param[in] *pSrcA points to the first input sequence. * @param[in] srcALen length of the first input sequence. * @param[in] *pSrcB points to the second input sequence. * @param[in] srcBLen length of the second input sequence. * @param[out] *pDst points to the block of output data Length 2 * max(srcALen, srcBLen) - 1. * @return none. */ void arm_correlate_q7( q7_t * pSrcA, uint32_t srcALen, q7_t * pSrcB, uint32_t srcBLen, q7_t * pDst); /** * @brief Instance structure for the floating-point sparse FIR filter. */ typedef struct { uint16_t numTaps; /**< number of coefficients in the filter. */ uint16_t stateIndex; /**< state buffer index. Points to the oldest sample in the state buffer. */ float32_t *pState; /**< points to the state buffer array. The array is of length maxDelay+blockSize-1. */ float32_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps.*/ uint16_t maxDelay; /**< maximum offset specified by the pTapDelay array. */ int32_t *pTapDelay; /**< points to the array of delay values. The array is of length numTaps. */ } arm_fir_sparse_instance_f32; /** * @brief Instance structure for the Q31 sparse FIR filter. */ typedef struct { uint16_t numTaps; /**< number of coefficients in the filter. */ uint16_t stateIndex; /**< state buffer index. Points to the oldest sample in the state buffer. */ q31_t *pState; /**< points to the state buffer array. The array is of length maxDelay+blockSize-1. */ q31_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps.*/ uint16_t maxDelay; /**< maximum offset specified by the pTapDelay array. */ int32_t *pTapDelay; /**< points to the array of delay values. The array is of length numTaps. */ } arm_fir_sparse_instance_q31; /** * @brief Instance structure for the Q15 sparse FIR filter. */ typedef struct { uint16_t numTaps; /**< number of coefficients in the filter. */ uint16_t stateIndex; /**< state buffer index. Points to the oldest sample in the state buffer. */ q15_t *pState; /**< points to the state buffer array. The array is of length maxDelay+blockSize-1. */ q15_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps.*/ uint16_t maxDelay; /**< maximum offset specified by the pTapDelay array. */ int32_t *pTapDelay; /**< points to the array of delay values. The array is of length numTaps. */ } arm_fir_sparse_instance_q15; /** * @brief Instance structure for the Q7 sparse FIR filter. */ typedef struct { uint16_t numTaps; /**< number of coefficients in the filter. */ uint16_t stateIndex; /**< state buffer index. Points to the oldest sample in the state buffer. */ q7_t *pState; /**< points to the state buffer array. The array is of length maxDelay+blockSize-1. */ q7_t *pCoeffs; /**< points to the coefficient array. The array is of length numTaps.*/ uint16_t maxDelay; /**< maximum offset specified by the pTapDelay array. */ int32_t *pTapDelay; /**< points to the array of delay values. The array is of length numTaps. */ } arm_fir_sparse_instance_q7; /** * @brief Processing function for the floating-point sparse FIR filter. * @param[in] *S points to an instance of the floating-point sparse FIR structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data * @param[in] *pScratchIn points to a temporary buffer of size blockSize. * @param[in] blockSize number of input samples to process per call. * @return none. */ void arm_fir_sparse_f32( arm_fir_sparse_instance_f32 * S, float32_t * pSrc, float32_t * pDst, float32_t * pScratchIn, uint32_t blockSize); /** * @brief Initialization function for the floating-point sparse FIR filter. * @param[in,out] *S points to an instance of the floating-point sparse FIR structure. * @param[in] numTaps number of nonzero coefficients in the filter. * @param[in] *pCoeffs points to the array of filter coefficients. * @param[in] *pState points to the state buffer. * @param[in] *pTapDelay points to the array of offset times. * @param[in] maxDelay maximum offset time supported. * @param[in] blockSize number of samples that will be processed per block. * @return none */ void arm_fir_sparse_init_f32( arm_fir_sparse_instance_f32 * S, uint16_t numTaps, float32_t * pCoeffs, float32_t * pState, int32_t * pTapDelay, uint16_t maxDelay, uint32_t blockSize); /** * @brief Processing function for the Q31 sparse FIR filter. * @param[in] *S points to an instance of the Q31 sparse FIR structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data * @param[in] *pScratchIn points to a temporary buffer of size blockSize. * @param[in] blockSize number of input samples to process per call. * @return none. */ void arm_fir_sparse_q31( arm_fir_sparse_instance_q31 * S, q31_t * pSrc, q31_t * pDst, q31_t * pScratchIn, uint32_t blockSize); /** * @brief Initialization function for the Q31 sparse FIR filter. * @param[in,out] *S points to an instance of the Q31 sparse FIR structure. * @param[in] numTaps number of nonzero coefficients in the filter. * @param[in] *pCoeffs points to the array of filter coefficients. * @param[in] *pState points to the state buffer. * @param[in] *pTapDelay points to the array of offset times. * @param[in] maxDelay maximum offset time supported. * @param[in] blockSize number of samples that will be processed per block. * @return none */ void arm_fir_sparse_init_q31( arm_fir_sparse_instance_q31 * S, uint16_t numTaps, q31_t * pCoeffs, q31_t * pState, int32_t * pTapDelay, uint16_t maxDelay, uint32_t blockSize); /** * @brief Processing function for the Q15 sparse FIR filter. * @param[in] *S points to an instance of the Q15 sparse FIR structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data * @param[in] *pScratchIn points to a temporary buffer of size blockSize. * @param[in] *pScratchOut points to a temporary buffer of size blockSize. * @param[in] blockSize number of input samples to process per call. * @return none. */ void arm_fir_sparse_q15( arm_fir_sparse_instance_q15 * S, q15_t * pSrc, q15_t * pDst, q15_t * pScratchIn, q31_t * pScratchOut, uint32_t blockSize); /** * @brief Initialization function for the Q15 sparse FIR filter. * @param[in,out] *S points to an instance of the Q15 sparse FIR structure. * @param[in] numTaps number of nonzero coefficients in the filter. * @param[in] *pCoeffs points to the array of filter coefficients. * @param[in] *pState points to the state buffer. * @param[in] *pTapDelay points to the array of offset times. * @param[in] maxDelay maximum offset time supported. * @param[in] blockSize number of samples that will be processed per block. * @return none */ void arm_fir_sparse_init_q15( arm_fir_sparse_instance_q15 * S, uint16_t numTaps, q15_t * pCoeffs, q15_t * pState, int32_t * pTapDelay, uint16_t maxDelay, uint32_t blockSize); /** * @brief Processing function for the Q7 sparse FIR filter. * @param[in] *S points to an instance of the Q7 sparse FIR structure. * @param[in] *pSrc points to the block of input data. * @param[out] *pDst points to the block of output data * @param[in] *pScratchIn points to a temporary buffer of size blockSize. * @param[in] *pScratchOut points to a temporary buffer of size blockSize. * @param[in] blockSize number of input samples to process per call. * @return none. */ void arm_fir_sparse_q7( arm_fir_sparse_instance_q7 * S, q7_t * pSrc, q7_t * pDst, q7_t * pScratchIn, q31_t * pScratchOut, uint32_t blockSize); /** * @brief Initialization function for the Q7 sparse FIR filter. * @param[in,out] *S points to an instance of the Q7 sparse FIR structure. * @param[in] numTaps number of nonzero coefficients in the filter. * @param[in] *pCoeffs points to the array of filter coefficients. * @param[in] *pState points to the state buffer. * @param[in] *pTapDelay points to the array of offset times. * @param[in] maxDelay maximum offset time supported. * @param[in] blockSize number of samples that will be processed per block. * @return none */ void arm_fir_sparse_init_q7( arm_fir_sparse_instance_q7 * S, uint16_t numTaps, q7_t * pCoeffs, q7_t * pState, int32_t * pTapDelay, uint16_t maxDelay, uint32_t blockSize); /* * @brief Floating-point sin_cos function. * @param[in] theta input value in degrees * @param[out] *pSinVal points to the processed sine output. * @param[out] *pCosVal points to the processed cos output. * @return none. */ void arm_sin_cos_f32( float32_t theta, float32_t * pSinVal, float32_t * pCcosVal); /* * @brief Q31 sin_cos function. * @param[in] theta scaled input value in degrees * @param[out] *pSinVal points to the processed sine output. * @param[out] *pCosVal points to the processed cosine output. * @return none. */ void arm_sin_cos_q31( q31_t theta, q31_t * pSinVal, q31_t * pCosVal); /** * @brief Floating-point complex conjugate. * @param[in] *pSrc points to the input vector * @param[out] *pDst points to the output vector * @param[in] numSamples number of complex samples in each vector * @return none. */ void arm_cmplx_conj_f32( float32_t * pSrc, float32_t * pDst, uint32_t numSamples); /** * @brief Q31 complex conjugate. * @param[in] *pSrc points to the input vector * @param[out] *pDst points to the output vector * @param[in] numSamples number of complex samples in each vector * @return none. */ void arm_cmplx_conj_q31( q31_t * pSrc, q31_t * pDst, uint32_t numSamples); /** * @brief Q15 complex conjugate. * @param[in] *pSrc points to the input vector * @param[out] *pDst points to the output vector * @param[in] numSamples number of complex samples in each vector * @return none. */ void arm_cmplx_conj_q15( q15_t * pSrc, q15_t * pDst, uint32_t numSamples); /** * @brief Floating-point complex magnitude squared * @param[in] *pSrc points to the complex input vector * @param[out] *pDst points to the real output vector * @param[in] numSamples number of complex samples in the input vector * @return none. */ void arm_cmplx_mag_squared_f32( float32_t * pSrc, float32_t * pDst, uint32_t numSamples); /** * @brief Q31 complex magnitude squared * @param[in] *pSrc points to the complex input vector * @param[out] *pDst points to the real output vector * @param[in] numSamples number of complex samples in the input vector * @return none. */ void arm_cmplx_mag_squared_q31( q31_t * pSrc, q31_t * pDst, uint32_t numSamples); /** * @brief Q15 complex magnitude squared * @param[in] *pSrc points to the complex input vector * @param[out] *pDst points to the real output vector * @param[in] numSamples number of complex samples in the input vector * @return none. */ void arm_cmplx_mag_squared_q15( q15_t * pSrc, q15_t * pDst, uint32_t numSamples); /** * @ingroup groupController */ /** * @defgroup PID PID Motor Control * * A Proportional Integral Derivative (PID) controller is a generic feedback control * loop mechanism widely used in industrial control systems. * A PID controller is the most commonly used type of feedback controller. * * This set of functions implements (PID) controllers * for Q15, Q31, and floating-point data types. The functions operate on a single sample * of data and each call to the function returns a single processed value. * <code>S</code> points to an instance of the PID control data structure. <code>in</code> * is the input sample value. The functions return the output value. * * \par Algorithm: * <pre> * y[n] = y[n-1] + A0 * x[n] + A1 * x[n-1] + A2 * x[n-2] * A0 = Kp + Ki + Kd * A1 = (-Kp ) - (2 * Kd ) * A2 = Kd </pre> * * \par * where \c Kp is proportional constant, \c Ki is Integral constant and \c Kd is Derivative constant * * \par * \image html PID.gif "Proportional Integral Derivative Controller" * * \par * The PID controller calculates an "error" value as the difference between * the measured output and the reference input. * The controller attempts to minimize the error by adjusting the process control inputs. * The proportional value determines the reaction to the current error, * the integral value determines the reaction based on the sum of recent errors, * and the derivative value determines the reaction based on the rate at which the error has been changing. * * \par Instance Structure * The Gains A0, A1, A2 and state variables for a PID controller are stored together in an instance data structure. * A separate instance structure must be defined for each PID Controller. * There are separate instance structure declarations for each of the 3 supported data types. * * \par Reset Functions * There is also an associated reset function for each data type which clears the state array. * * \par Initialization Functions * There is also an associated initialization function for each data type. * The initialization function performs the following operations: * - Initializes the Gains A0, A1, A2 from Kp,Ki, Kd gains. * - Zeros out the values in the state buffer. * * \par * Instance structure cannot be placed into a const data section and it is recommended to use the initialization function. * * \par Fixed-Point Behavior * Care must be taken when using the fixed-point versions of the PID Controller functions. * In particular, the overflow and saturation behavior of the accumulator used in each function must be considered. * Refer to the function specific documentation below for usage guidelines. */ /** * @addtogroup PID * @{ */ /** * @brief Process function for the floating-point PID Control. * @param[in,out] *S is an instance of the floating-point PID Control structure * @param[in] in input sample to process * @return out processed output sample. */ static __INLINE float32_t arm_pid_f32( arm_pid_instance_f32 * S, float32_t in) { float32_t out; /* y[n] = y[n-1] + A0 * x[n] + A1 * x[n-1] + A2 * x[n-2] */ out = (S->A0 * in) + (S->A1 * S->state[0]) + (S->A2 * S->state[1]) + (S->state[2]); /* Update state */ S->state[1] = S->state[0]; S->state[0] = in; S->state[2] = out; /* return to application */ return (out); } /** * @brief Process function for the Q31 PID Control. * @param[in,out] *S points to an instance of the Q31 PID Control structure * @param[in] in input sample to process * @return out processed output sample. * * <b>Scaling and Overflow Behavior:</b> * \par * The function is implemented using an internal 64-bit accumulator. * The accumulator has a 2.62 format and maintains full precision of the intermediate multiplication results but provides only a single guard bit. * Thus, if the accumulator result overflows it wraps around rather than clip. * In order to avoid overflows completely the input signal must be scaled down by 2 bits as there are four additions. * After all multiply-accumulates are performed, the 2.62 accumulator is truncated to 1.32 format and then saturated to 1.31 format. */ static __INLINE q31_t arm_pid_q31( arm_pid_instance_q31 * S, q31_t in) { q63_t acc; q31_t out; /* acc = A0 * x[n] */ acc = (q63_t) S->A0 * in; /* acc += A1 * x[n-1] */ acc += (q63_t) S->A1 * S->state[0]; /* acc += A2 * x[n-2] */ acc += (q63_t) S->A2 * S->state[1]; /* convert output to 1.31 format to add y[n-1] */ out = (q31_t) (acc >> 31u); /* out += y[n-1] */ out += S->state[2]; /* Update state */ S->state[1] = S->state[0]; S->state[0] = in; S->state[2] = out; /* return to application */ return (out); } /** * @brief Process function for the Q15 PID Control. * @param[in,out] *S points to an instance of the Q15 PID Control structure * @param[in] in input sample to process * @return out processed output sample. * * <b>Scaling and Overflow Behavior:</b> * \par * The function is implemented using a 64-bit internal accumulator. * Both Gains and state variables are represented in 1.15 format and multiplications yield a 2.30 result. * The 2.30 intermediate results are accumulated in a 64-bit accumulator in 34.30 format. * There is no risk of internal overflow with this approach and the full precision of intermediate multiplications is preserved. * After all additions have been performed, the accumulator is truncated to 34.15 format by discarding low 15 bits. * Lastly, the accumulator is saturated to yield a result in 1.15 format. */ static __INLINE q15_t arm_pid_q15( arm_pid_instance_q15 * S, q15_t in) { q63_t acc; q15_t out; #ifndef ARM_MATH_CM0_FAMILY __SIMD32_TYPE *vstate; /* Implementation of PID controller */ /* acc = A0 * x[n] */ acc = (q31_t) __SMUAD(S->A0, in); /* acc += A1 * x[n-1] + A2 * x[n-2] */ vstate = __SIMD32_CONST(S->state); acc = __SMLALD(S->A1, (q31_t) *vstate, acc); #else /* acc = A0 * x[n] */ acc = ((q31_t) S->A0) * in; /* acc += A1 * x[n-1] + A2 * x[n-2] */ acc += (q31_t) S->A1 * S->state[0]; acc += (q31_t) S->A2 * S->state[1]; #endif /* acc += y[n-1] */ acc += (q31_t) S->state[2] << 15; /* saturate the output */ out = (q15_t) (__SSAT((acc >> 15), 16)); /* Update state */ S->state[1] = S->state[0]; S->state[0] = in; S->state[2] = out; /* return to application */ return (out); } /** * @} end of PID group */ /** * @brief Floating-point matrix inverse. * @param[in] *src points to the instance of the input floating-point matrix structure. * @param[out] *dst points to the instance of the output floating-point matrix structure. * @return The function returns ARM_MATH_SIZE_MISMATCH, if the dimensions do not match. * If the input matrix is singular (does not have an inverse), then the algorithm terminates and returns error status ARM_MATH_SINGULAR. */ arm_status arm_mat_inverse_f32( const arm_matrix_instance_f32 * src, arm_matrix_instance_f32 * dst); /** * @brief Floating-point matrix inverse. * @param[in] *src points to the instance of the input floating-point matrix structure. * @param[out] *dst points to the instance of the output floating-point matrix structure. * @return The function returns ARM_MATH_SIZE_MISMATCH, if the dimensions do not match. * If the input matrix is singular (does not have an inverse), then the algorithm terminates and returns error status ARM_MATH_SINGULAR. */ arm_status arm_mat_inverse_f64( const arm_matrix_instance_f64 * src, arm_matrix_instance_f64 * dst); /** * @ingroup groupController */ /** * @defgroup clarke Vector Clarke Transform * Forward Clarke transform converts the instantaneous stator phases into a two-coordinate time invariant vector. * Generally the Clarke transform uses three-phase currents <code>Ia, Ib and Ic</code> to calculate currents * in the two-phase orthogonal stator axis <code>Ialpha</code> and <code>Ibeta</code>. * When <code>Ialpha</code> is superposed with <code>Ia</code> as shown in the figure below * \image html clarke.gif Stator current space vector and its components in (a,b). * and <code>Ia + Ib + Ic = 0</code>, in this condition <code>Ialpha</code> and <code>Ibeta</code> * can be calculated using only <code>Ia</code> and <code>Ib</code>. * * The function operates on a single sample of data and each call to the function returns the processed output. * The library provides separate functions for Q31 and floating-point data types. * \par Algorithm * \image html clarkeFormula.gif * where <code>Ia</code> and <code>Ib</code> are the instantaneous stator phases and * <code>pIalpha</code> and <code>pIbeta</code> are the two coordinates of time invariant vector. * \par Fixed-Point Behavior * Care must be taken when using the Q31 version of the Clarke transform. * In particular, the overflow and saturation behavior of the accumulator used must be considered. * Refer to the function specific documentation below for usage guidelines. */ /** * @addtogroup clarke * @{ */ /** * * @brief Floating-point Clarke transform * @param[in] Ia input three-phase coordinate <code>a</code> * @param[in] Ib input three-phase coordinate <code>b</code> * @param[out] *pIalpha points to output two-phase orthogonal vector axis alpha * @param[out] *pIbeta points to output two-phase orthogonal vector axis beta * @return none. */ static __INLINE void arm_clarke_f32( float32_t Ia, float32_t Ib, float32_t * pIalpha, float32_t * pIbeta) { /* Calculate pIalpha using the equation, pIalpha = Ia */ *pIalpha = Ia; /* Calculate pIbeta using the equation, pIbeta = (1/sqrt(3)) * Ia + (2/sqrt(3)) * Ib */ *pIbeta = ((float32_t) 0.57735026919 * Ia + (float32_t) 1.15470053838 * Ib); } /** * @brief Clarke transform for Q31 version * @param[in] Ia input three-phase coordinate <code>a</code> * @param[in] Ib input three-phase coordinate <code>b</code> * @param[out] *pIalpha points to output two-phase orthogonal vector axis alpha * @param[out] *pIbeta points to output two-phase orthogonal vector axis beta * @return none. * * <b>Scaling and Overflow Behavior:</b> * \par * The function is implemented using an internal 32-bit accumulator. * The accumulator maintains 1.31 format by truncating lower 31 bits of the intermediate multiplication in 2.62 format. * There is saturation on the addition, hence there is no risk of overflow. */ static __INLINE void arm_clarke_q31( q31_t Ia, q31_t Ib, q31_t * pIalpha, q31_t * pIbeta) { q31_t product1, product2; /* Temporary variables used to store intermediate results */ /* Calculating pIalpha from Ia by equation pIalpha = Ia */ *pIalpha = Ia; /* Intermediate product is calculated by (1/(sqrt(3)) * Ia) */ product1 = (q31_t) (((q63_t) Ia * 0x24F34E8B) >> 30); /* Intermediate product is calculated by (2/sqrt(3) * Ib) */ product2 = (q31_t) (((q63_t) Ib * 0x49E69D16) >> 30); /* pIbeta is calculated by adding the intermediate products */ *pIbeta = __QADD(product1, product2); } /** * @} end of clarke group */ /** * @brief Converts the elements of the Q7 vector to Q31 vector. * @param[in] *pSrc input pointer * @param[out] *pDst output pointer * @param[in] blockSize number of samples to process * @return none. */ void arm_q7_to_q31( q7_t * pSrc, q31_t * pDst, uint32_t blockSize); /** * @ingroup groupController */ /** * @defgroup inv_clarke Vector Inverse Clarke Transform * Inverse Clarke transform converts the two-coordinate time invariant vector into instantaneous stator phases. * * The function operates on a single sample of data and each call to the function returns the processed output. * The library provides separate functions for Q31 and floating-point data types. * \par Algorithm * \image html clarkeInvFormula.gif * where <code>pIa</code> and <code>pIb</code> are the instantaneous stator phases and * <code>Ialpha</code> and <code>Ibeta</code> are the two coordinates of time invariant vector. * \par Fixed-Point Behavior * Care must be taken when using the Q31 version of the Clarke transform. * In particular, the overflow and saturation behavior of the accumulator used must be considered. * Refer to the function specific documentation below for usage guidelines. */ /** * @addtogroup inv_clarke * @{ */ /** * @brief Floating-point Inverse Clarke transform * @param[in] Ialpha input two-phase orthogonal vector axis alpha * @param[in] Ibeta input two-phase orthogonal vector axis beta * @param[out] *pIa points to output three-phase coordinate <code>a</code> * @param[out] *pIb points to output three-phase coordinate <code>b</code> * @return none. */ static __INLINE void arm_inv_clarke_f32( float32_t Ialpha, float32_t Ibeta, float32_t * pIa, float32_t * pIb) { /* Calculating pIa from Ialpha by equation pIa = Ialpha */ *pIa = Ialpha; /* Calculating pIb from Ialpha and Ibeta by equation pIb = -(1/2) * Ialpha + (sqrt(3)/2) * Ibeta */ *pIb = -0.5 * Ialpha + (float32_t) 0.8660254039 *Ibeta; } /** * @brief Inverse Clarke transform for Q31 version * @param[in] Ialpha input two-phase orthogonal vector axis alpha * @param[in] Ibeta input two-phase orthogonal vector axis beta * @param[out] *pIa points to output three-phase coordinate <code>a</code> * @param[out] *pIb points to output three-phase coordinate <code>b</code> * @return none. * * <b>Scaling and Overflow Behavior:</b> * \par * The function is implemented using an internal 32-bit accumulator. * The accumulator maintains 1.31 format by truncating lower 31 bits of the intermediate multiplication in 2.62 format. * There is saturation on the subtraction, hence there is no risk of overflow. */ static __INLINE void arm_inv_clarke_q31( q31_t Ialpha, q31_t Ibeta, q31_t * pIa, q31_t * pIb) { q31_t product1, product2; /* Temporary variables used to store intermediate results */ /* Calculating pIa from Ialpha by equation pIa = Ialpha */ *pIa = Ialpha; /* Intermediate product is calculated by (1/(2*sqrt(3)) * Ia) */ product1 = (q31_t) (((q63_t) (Ialpha) * (0x40000000)) >> 31); /* Intermediate product is calculated by (1/sqrt(3) * pIb) */ product2 = (q31_t) (((q63_t) (Ibeta) * (0x6ED9EBA1)) >> 31); /* pIb is calculated by subtracting the products */ *pIb = __QSUB(product2, product1); } /** * @} end of inv_clarke group */ /** * @brief Converts the elements of the Q7 vector to Q15 vector. * @param[in] *pSrc input pointer * @param[out] *pDst output pointer * @param[in] blockSize number of samples to process * @return none. */ void arm_q7_to_q15( q7_t * pSrc, q15_t * pDst, uint32_t blockSize); /** * @ingroup groupController */ /** * @defgroup park Vector Park Transform * * Forward Park transform converts the input two-coordinate vector to flux and torque components. * The Park transform can be used to realize the transformation of the <code>Ialpha</code> and the <code>Ibeta</code> currents * from the stationary to the moving reference frame and control the spatial relationship between * the stator vector current and rotor flux vector. * If we consider the d axis aligned with the rotor flux, the diagram below shows the * current vector and the relationship from the two reference frames: * \image html park.gif "Stator current space vector and its component in (a,b) and in the d,q rotating reference frame" * * The function operates on a single sample of data and each call to the function returns the processed output. * The library provides separate functions for Q31 and floating-point data types. * \par Algorithm * \image html parkFormula.gif * where <code>Ialpha</code> and <code>Ibeta</code> are the stator vector components, * <code>pId</code> and <code>pIq</code> are rotor vector components and <code>cosVal</code> and <code>sinVal</code> are the * cosine and sine values of theta (rotor flux position). * \par Fixed-Point Behavior * Care must be taken when using the Q31 version of the Park transform. * In particular, the overflow and saturation behavior of the accumulator used must be considered. * Refer to the function specific documentation below for usage guidelines. */ /** * @addtogroup park * @{ */ /** * @brief Floating-point Park transform * @param[in] Ialpha input two-phase vector coordinate alpha * @param[in] Ibeta input two-phase vector coordinate beta * @param[out] *pId points to output rotor reference frame d * @param[out] *pIq points to output rotor reference frame q * @param[in] sinVal sine value of rotation angle theta * @param[in] cosVal cosine value of rotation angle theta * @return none. * * The function implements the forward Park transform. * */ static __INLINE void arm_park_f32( float32_t Ialpha, float32_t Ibeta, float32_t * pId, float32_t * pIq, float32_t sinVal, float32_t cosVal) { /* Calculate pId using the equation, pId = Ialpha * cosVal + Ibeta * sinVal */ *pId = Ialpha * cosVal + Ibeta * sinVal; /* Calculate pIq using the equation, pIq = - Ialpha * sinVal + Ibeta * cosVal */ *pIq = -Ialpha * sinVal + Ibeta * cosVal; } /** * @brief Park transform for Q31 version * @param[in] Ialpha input two-phase vector coordinate alpha * @param[in] Ibeta input two-phase vector coordinate beta * @param[out] *pId points to output rotor reference frame d * @param[out] *pIq points to output rotor reference frame q * @param[in] sinVal sine value of rotation angle theta * @param[in] cosVal cosine value of rotation angle theta * @return none. * * <b>Scaling and Overflow Behavior:</b> * \par * The function is implemented using an internal 32-bit accumulator. * The accumulator maintains 1.31 format by truncating lower 31 bits of the intermediate multiplication in 2.62 format. * There is saturation on the addition and subtraction, hence there is no risk of overflow. */ static __INLINE void arm_park_q31( q31_t Ialpha, q31_t Ibeta, q31_t * pId, q31_t * pIq, q31_t sinVal, q31_t cosVal) { q31_t product1, product2; /* Temporary variables used to store intermediate results */ q31_t product3, product4; /* Temporary variables used to store intermediate results */ /* Intermediate product is calculated by (Ialpha * cosVal) */ product1 = (q31_t) (((q63_t) (Ialpha) * (cosVal)) >> 31); /* Intermediate product is calculated by (Ibeta * sinVal) */ product2 = (q31_t) (((q63_t) (Ibeta) * (sinVal)) >> 31); /* Intermediate product is calculated by (Ialpha * sinVal) */ product3 = (q31_t) (((q63_t) (Ialpha) * (sinVal)) >> 31); /* Intermediate product is calculated by (Ibeta * cosVal) */ product4 = (q31_t) (((q63_t) (Ibeta) * (cosVal)) >> 31); /* Calculate pId by adding the two intermediate products 1 and 2 */ *pId = __QADD(product1, product2); /* Calculate pIq by subtracting the two intermediate products 3 from 4 */ *pIq = __QSUB(product4, product3); } /** * @} end of park group */ /** * @brief Converts the elements of the Q7 vector to floating-point vector. * @param[in] *pSrc is input pointer * @param[out] *pDst is output pointer * @param[in] blockSize is the number of samples to process * @return none. */ void arm_q7_to_float( q7_t * pSrc, float32_t * pDst, uint32_t blockSize); /** * @ingroup groupController */ /** * @defgroup inv_park Vector Inverse Park transform * Inverse Park transform converts the input flux and torque components to two-coordinate vector. * * The function operates on a single sample of data and each call to the function returns the processed output. * The library provides separate functions for Q31 and floating-point data types. * \par Algorithm * \image html parkInvFormula.gif * where <code>pIalpha</code> and <code>pIbeta</code> are the stator vector components, * <code>Id</code> and <code>Iq</code> are rotor vector components and <code>cosVal</code> and <code>sinVal</code> are the * cosine and sine values of theta (rotor flux position). * \par Fixed-Point Behavior * Care must be taken when using the Q31 version of the Park transform. * In particular, the overflow and saturation behavior of the accumulator used must be considered. * Refer to the function specific documentation below for usage guidelines. */ /** * @addtogroup inv_park * @{ */ /** * @brief Floating-point Inverse Park transform * @param[in] Id input coordinate of rotor reference frame d * @param[in] Iq input coordinate of rotor reference frame q * @param[out] *pIalpha points to output two-phase orthogonal vector axis alpha * @param[out] *pIbeta points to output two-phase orthogonal vector axis beta * @param[in] sinVal sine value of rotation angle theta * @param[in] cosVal cosine value of rotation angle theta * @return none. */ static __INLINE void arm_inv_park_f32( float32_t Id, float32_t Iq, float32_t * pIalpha, float32_t * pIbeta, float32_t sinVal, float32_t cosVal) { /* Calculate pIalpha using the equation, pIalpha = Id * cosVal - Iq * sinVal */ *pIalpha = Id * cosVal - Iq * sinVal; /* Calculate pIbeta using the equation, pIbeta = Id * sinVal + Iq * cosVal */ *pIbeta = Id * sinVal + Iq * cosVal; } /** * @brief Inverse Park transform for Q31 version * @param[in] Id input coordinate of rotor reference frame d * @param[in] Iq input coordinate of rotor reference frame q * @param[out] *pIalpha points to output two-phase orthogonal vector axis alpha * @param[out] *pIbeta points to output two-phase orthogonal vector axis beta * @param[in] sinVal sine value of rotation angle theta * @param[in] cosVal cosine value of rotation angle theta * @return none. * * <b>Scaling and Overflow Behavior:</b> * \par * The function is implemented using an internal 32-bit accumulator. * The accumulator maintains 1.31 format by truncating lower 31 bits of the intermediate multiplication in 2.62 format. * There is saturation on the addition, hence there is no risk of overflow. */ static __INLINE void arm_inv_park_q31( q31_t Id, q31_t Iq, q31_t * pIalpha, q31_t * pIbeta, q31_t sinVal, q31_t cosVal) { q31_t product1, product2; /* Temporary variables used to store intermediate results */ q31_t product3, product4; /* Temporary variables used to store intermediate results */ /* Intermediate product is calculated by (Id * cosVal) */ product1 = (q31_t) (((q63_t) (Id) * (cosVal)) >> 31); /* Intermediate product is calculated by (Iq * sinVal) */ product2 = (q31_t) (((q63_t) (Iq) * (sinVal)) >> 31); /* Intermediate product is calculated by (Id * sinVal) */ product3 = (q31_t) (((q63_t) (Id) * (sinVal)) >> 31); /* Intermediate product is calculated by (Iq * cosVal) */ product4 = (q31_t) (((q63_t) (Iq) * (cosVal)) >> 31); /* Calculate pIalpha by using the two intermediate products 1 and 2 */ *pIalpha = __QSUB(product1, product2); /* Calculate pIbeta by using the two intermediate products 3 and 4 */ *pIbeta = __QADD(product4, product3); } /** * @} end of Inverse park group */ /** * @brief Converts the elements of the Q31 vector to floating-point vector. * @param[in] *pSrc is input pointer * @param[out] *pDst is output pointer * @param[in] blockSize is the number of samples to process * @return none. */ void arm_q31_to_float( q31_t * pSrc, float32_t * pDst, uint32_t blockSize); /** * @ingroup groupInterpolation */ /** * @defgroup LinearInterpolate Linear Interpolation * * Linear interpolation is a method of curve fitting using linear polynomials. * Linear interpolation works by effectively drawing a straight line between two neighboring samples and returning the appropriate point along that line * * \par * \image html LinearInterp.gif "Linear interpolation" * * \par * A Linear Interpolate function calculates an output value(y), for the input(x) * using linear interpolation of the input values x0, x1( nearest input values) and the output values y0 and y1(nearest output values) * * \par Algorithm: * <pre> * y = y0 + (x - x0) * ((y1 - y0)/(x1-x0)) * where x0, x1 are nearest values of input x * y0, y1 are nearest values to output y * </pre> * * \par * This set of functions implements Linear interpolation process * for Q7, Q15, Q31, and floating-point data types. The functions operate on a single * sample of data and each call to the function returns a single processed value. * <code>S</code> points to an instance of the Linear Interpolate function data structure. * <code>x</code> is the input sample value. The functions returns the output value. * * \par * if x is outside of the table boundary, Linear interpolation returns first value of the table * if x is below input range and returns last value of table if x is above range. */ /** * @addtogroup LinearInterpolate * @{ */ /** * @brief Process function for the floating-point Linear Interpolation Function. * @param[in,out] *S is an instance of the floating-point Linear Interpolation structure * @param[in] x input sample to process * @return y processed output sample. * */ static __INLINE float32_t arm_linear_interp_f32( arm_linear_interp_instance_f32 * S, float32_t x) { float32_t y; float32_t x0, x1; /* Nearest input values */ float32_t y0, y1; /* Nearest output values */ float32_t xSpacing = S->xSpacing; /* spacing between input values */ int32_t i; /* Index variable */ float32_t *pYData = S->pYData; /* pointer to output table */ /* Calculation of index */ i = (int32_t) ((x - S->x1) / xSpacing); if(i < 0) { /* Iniatilize output for below specified range as least output value of table */ y = pYData[0]; } else if((uint32_t)i >= S->nValues) { /* Iniatilize output for above specified range as last output value of table */ y = pYData[S->nValues - 1]; } else { /* Calculation of nearest input values */ x0 = S->x1 + i * xSpacing; x1 = S->x1 + (i + 1) * xSpacing; /* Read of nearest output values */ y0 = pYData[i]; y1 = pYData[i + 1]; /* Calculation of output */ y = y0 + (x - x0) * ((y1 - y0) / (x1 - x0)); } /* returns output value */ return (y); } /** * * @brief Process function for the Q31 Linear Interpolation Function. * @param[in] *pYData pointer to Q31 Linear Interpolation table * @param[in] x input sample to process * @param[in] nValues number of table values * @return y processed output sample. * * \par * Input sample <code>x</code> is in 12.20 format which contains 12 bits for table index and 20 bits for fractional part. * This function can support maximum of table size 2^12. * */ static __INLINE q31_t arm_linear_interp_q31( q31_t * pYData, q31_t x, uint32_t nValues) { q31_t y; /* output */ q31_t y0, y1; /* Nearest output values */ q31_t fract; /* fractional part */ int32_t index; /* Index to read nearest output values */ /* Input is in 12.20 format */ /* 12 bits for the table index */ /* Index value calculation */ index = ((x & 0xFFF00000) >> 20); if(index >= (int32_t)(nValues - 1)) { return (pYData[nValues - 1]); } else if(index < 0) { return (pYData[0]); } else { /* 20 bits for the fractional part */ /* shift left by 11 to keep fract in 1.31 format */ fract = (x & 0x000FFFFF) << 11; /* Read two nearest output values from the index in 1.31(q31) format */ y0 = pYData[index]; y1 = pYData[index + 1u]; /* Calculation of y0 * (1-fract) and y is in 2.30 format */ y = ((q31_t) ((q63_t) y0 * (0x7FFFFFFF - fract) >> 32)); /* Calculation of y0 * (1-fract) + y1 *fract and y is in 2.30 format */ y += ((q31_t) (((q63_t) y1 * fract) >> 32)); /* Convert y to 1.31 format */ return (y << 1u); } } /** * * @brief Process function for the Q15 Linear Interpolation Function. * @param[in] *pYData pointer to Q15 Linear Interpolation table * @param[in] x input sample to process * @param[in] nValues number of table values * @return y processed output sample. * * \par * Input sample <code>x</code> is in 12.20 format which contains 12 bits for table index and 20 bits for fractional part. * This function can support maximum of table size 2^12. * */ static __INLINE q15_t arm_linear_interp_q15( q15_t * pYData, q31_t x, uint32_t nValues) { q63_t y; /* output */ q15_t y0, y1; /* Nearest output values */ q31_t fract; /* fractional part */ int32_t index; /* Index to read nearest output values */ /* Input is in 12.20 format */ /* 12 bits for the table index */ /* Index value calculation */ index = ((x & 0xFFF00000) >> 20u); if(index >= (int32_t)(nValues - 1)) { return (pYData[nValues - 1]); } else if(index < 0) { return (pYData[0]); } else { /* 20 bits for the fractional part */ /* fract is in 12.20 format */ fract = (x & 0x000FFFFF); /* Read two nearest output values from the index */ y0 = pYData[index]; y1 = pYData[index + 1u]; /* Calculation of y0 * (1-fract) and y is in 13.35 format */ y = ((q63_t) y0 * (0xFFFFF - fract)); /* Calculation of (y0 * (1-fract) + y1 * fract) and y is in 13.35 format */ y += ((q63_t) y1 * (fract)); /* convert y to 1.15 format */ return (y >> 20); } } /** * * @brief Process function for the Q7 Linear Interpolation Function. * @param[in] *pYData pointer to Q7 Linear Interpolation table * @param[in] x input sample to process * @param[in] nValues number of table values * @return y processed output sample. * * \par * Input sample <code>x</code> is in 12.20 format which contains 12 bits for table index and 20 bits for fractional part. * This function can support maximum of table size 2^12. */ static __INLINE q7_t arm_linear_interp_q7( q7_t * pYData, q31_t x, uint32_t nValues) { q31_t y; /* output */ q7_t y0, y1; /* Nearest output values */ q31_t fract; /* fractional part */ uint32_t index; /* Index to read nearest output values */ /* Input is in 12.20 format */ /* 12 bits for the table index */ /* Index value calculation */ if (x < 0) { return (pYData[0]); } index = (x >> 20) & 0xfff; if(index >= (nValues - 1)) { return (pYData[nValues - 1]); } else { /* 20 bits for the fractional part */ /* fract is in 12.20 format */ fract = (x & 0x000FFFFF); /* Read two nearest output values from the index and are in 1.7(q7) format */ y0 = pYData[index]; y1 = pYData[index + 1u]; /* Calculation of y0 * (1-fract ) and y is in 13.27(q27) format */ y = ((y0 * (0xFFFFF - fract))); /* Calculation of y1 * fract + y0 * (1-fract) and y is in 13.27(q27) format */ y += (y1 * fract); /* convert y to 1.7(q7) format */ return (y >> 20u); } } /** * @} end of LinearInterpolate group */ /** * @brief Fast approximation to the trigonometric sine function for floating-point data. * @param[in] x input value in radians. * @return sin(x). */ float32_t arm_sin_f32( float32_t x); /** * @brief Fast approximation to the trigonometric sine function for Q31 data. * @param[in] x Scaled input value in radians. * @return sin(x). */ q31_t arm_sin_q31( q31_t x); /** * @brief Fast approximation to the trigonometric sine function for Q15 data. * @param[in] x Scaled input value in radians. * @return sin(x). */ q15_t arm_sin_q15( q15_t x); /** * @brief Fast approximation to the trigonometric cosine function for floating-point data. * @param[in] x input value in radians. * @return cos(x). */ float32_t arm_cos_f32( float32_t x); /** * @brief Fast approximation to the trigonometric cosine function for Q31 data. * @param[in] x Scaled input value in radians. * @return cos(x). */ q31_t arm_cos_q31( q31_t x); /** * @brief Fast approximation to the trigonometric cosine function for Q15 data. * @param[in] x Scaled input value in radians. * @return cos(x). */ q15_t arm_cos_q15( q15_t x); /** * @ingroup groupFastMath */ /** * @defgroup SQRT Square Root * * Computes the square root of a number. * There are separate functions for Q15, Q31, and floating-point data types. * The square root function is computed using the Newton-Raphson algorithm. * This is an iterative algorithm of the form: * <pre> * x1 = x0 - f(x0)/f'(x0) * </pre> * where <code>x1</code> is the current estimate, * <code>x0</code> is the previous estimate, and * <code>f'(x0)</code> is the derivative of <code>f()</code> evaluated at <code>x0</code>. * For the square root function, the algorithm reduces to: * <pre> * x0 = in/2 [initial guess] * x1 = 1/2 * ( x0 + in / x0) [each iteration] * </pre> */ /** * @addtogroup SQRT * @{ */ /** * @brief Floating-point square root function. * @param[in] in input value. * @param[out] *pOut square root of input value. * @return The function returns ARM_MATH_SUCCESS if input value is positive value or ARM_MATH_ARGUMENT_ERROR if * <code>in</code> is negative value and returns zero output for negative values. */ static __INLINE arm_status arm_sqrt_f32( float32_t in, float32_t * pOut) { if(in >= 0.0f) { // #if __FPU_USED #if (__FPU_USED == 1) && defined ( __CC_ARM ) *pOut = __sqrtf(in); #else *pOut = sqrtf(in); #endif return (ARM_MATH_SUCCESS); } else { *pOut = 0.0f; return (ARM_MATH_ARGUMENT_ERROR); } } /** * @brief Q31 square root function. * @param[in] in input value. The range of the input value is [0 +1) or 0x00000000 to 0x7FFFFFFF. * @param[out] *pOut square root of input value. * @return The function returns ARM_MATH_SUCCESS if input value is positive value or ARM_MATH_ARGUMENT_ERROR if * <code>in</code> is negative value and returns zero output for negative values. */ arm_status arm_sqrt_q31( q31_t in, q31_t * pOut); /** * @brief Q15 square root function. * @param[in] in input value. The range of the input value is [0 +1) or 0x0000 to 0x7FFF. * @param[out] *pOut square root of input value. * @return The function returns ARM_MATH_SUCCESS if input value is positive value or ARM_MATH_ARGUMENT_ERROR if * <code>in</code> is negative value and returns zero output for negative values. */ arm_status arm_sqrt_q15( q15_t in, q15_t * pOut); /** * @} end of SQRT group */ /** * @brief floating-point Circular write function. */ static __INLINE void arm_circularWrite_f32( int32_t * circBuffer, int32_t L, uint16_t * writeOffset, int32_t bufferInc, const int32_t * src, int32_t srcInc, uint32_t blockSize) { uint32_t i = 0u; int32_t wOffset; /* Copy the value of Index pointer that points * to the current location where the input samples to be copied */ wOffset = *writeOffset; /* Loop over the blockSize */ i = blockSize; while(i > 0u) { /* copy the input sample to the circular buffer */ circBuffer[wOffset] = *src; /* Update the input pointer */ src += srcInc; /* Circularly update wOffset. Watch out for positive and negative value */ wOffset += bufferInc; if(wOffset >= L) wOffset -= L; /* Decrement the loop counter */ i--; } /* Update the index pointer */ *writeOffset = wOffset; } /** * @brief floating-point Circular Read function. */ static __INLINE void arm_circularRead_f32( int32_t * circBuffer, int32_t L, int32_t * readOffset, int32_t bufferInc, int32_t * dst, int32_t * dst_base, int32_t dst_length, int32_t dstInc, uint32_t blockSize) { uint32_t i = 0u; int32_t rOffset, dst_end; /* Copy the value of Index pointer that points * to the current location from where the input samples to be read */ rOffset = *readOffset; dst_end = (int32_t) (dst_base + dst_length); /* Loop over the blockSize */ i = blockSize; while(i > 0u) { /* copy the sample from the circular buffer to the destination buffer */ *dst = circBuffer[rOffset]; /* Update the input pointer */ dst += dstInc; if(dst == (int32_t *) dst_end) { dst = dst_base; } /* Circularly update rOffset. Watch out for positive and negative value */ rOffset += bufferInc; if(rOffset >= L) { rOffset -= L; } /* Decrement the loop counter */ i--; } /* Update the index pointer */ *readOffset = rOffset; } /** * @brief Q15 Circular write function. */ static __INLINE void arm_circularWrite_q15( q15_t * circBuffer, int32_t L, uint16_t * writeOffset, int32_t bufferInc, const q15_t * src, int32_t srcInc, uint32_t blockSize) { uint32_t i = 0u; int32_t wOffset; /* Copy the value of Index pointer that points * to the current location where the input samples to be copied */ wOffset = *writeOffset; /* Loop over the blockSize */ i = blockSize; while(i > 0u) { /* copy the input sample to the circular buffer */ circBuffer[wOffset] = *src; /* Update the input pointer */ src += srcInc; /* Circularly update wOffset. Watch out for positive and negative value */ wOffset += bufferInc; if(wOffset >= L) wOffset -= L; /* Decrement the loop counter */ i--; } /* Update the index pointer */ *writeOffset = wOffset; } /** * @brief Q15 Circular Read function. */ static __INLINE void arm_circularRead_q15( q15_t * circBuffer, int32_t L, int32_t * readOffset, int32_t bufferInc, q15_t * dst, q15_t * dst_base, int32_t dst_length, int32_t dstInc, uint32_t blockSize) { uint32_t i = 0; int32_t rOffset, dst_end; /* Copy the value of Index pointer that points * to the current location from where the input samples to be read */ rOffset = *readOffset; dst_end = (int32_t) (dst_base + dst_length); /* Loop over the blockSize */ i = blockSize; while(i > 0u) { /* copy the sample from the circular buffer to the destination buffer */ *dst = circBuffer[rOffset]; /* Update the input pointer */ dst += dstInc; if(dst == (q15_t *) dst_end) { dst = dst_base; } /* Circularly update wOffset. Watch out for positive and negative value */ rOffset += bufferInc; if(rOffset >= L) { rOffset -= L; } /* Decrement the loop counter */ i--; } /* Update the index pointer */ *readOffset = rOffset; } /** * @brief Q7 Circular write function. */ static __INLINE void arm_circularWrite_q7( q7_t * circBuffer, int32_t L, uint16_t * writeOffset, int32_t bufferInc, const q7_t * src, int32_t srcInc, uint32_t blockSize) { uint32_t i = 0u; int32_t wOffset; /* Copy the value of Index pointer that points * to the current location where the input samples to be copied */ wOffset = *writeOffset; /* Loop over the blockSize */ i = blockSize; while(i > 0u) { /* copy the input sample to the circular buffer */ circBuffer[wOffset] = *src; /* Update the input pointer */ src += srcInc; /* Circularly update wOffset. Watch out for positive and negative value */ wOffset += bufferInc; if(wOffset >= L) wOffset -= L; /* Decrement the loop counter */ i--; } /* Update the index pointer */ *writeOffset = wOffset; } /** * @brief Q7 Circular Read function. */ static __INLINE void arm_circularRead_q7( q7_t * circBuffer, int32_t L, int32_t * readOffset, int32_t bufferInc, q7_t * dst, q7_t * dst_base, int32_t dst_length, int32_t dstInc, uint32_t blockSize) { uint32_t i = 0; int32_t rOffset, dst_end; /* Copy the value of Index pointer that points * to the current location from where the input samples to be read */ rOffset = *readOffset; dst_end = (int32_t) (dst_base + dst_length); /* Loop over the blockSize */ i = blockSize; while(i > 0u) { /* copy the sample from the circular buffer to the destination buffer */ *dst = circBuffer[rOffset]; /* Update the input pointer */ dst += dstInc; if(dst == (q7_t *) dst_end) { dst = dst_base; } /* Circularly update rOffset. Watch out for positive and negative value */ rOffset += bufferInc; if(rOffset >= L) { rOffset -= L; } /* Decrement the loop counter */ i--; } /* Update the index pointer */ *readOffset = rOffset; } /** * @brief Sum of the squares of the elements of a Q31 vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output value. * @return none. */ void arm_power_q31( q31_t * pSrc, uint32_t blockSize, q63_t * pResult); /** * @brief Sum of the squares of the elements of a floating-point vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output value. * @return none. */ void arm_power_f32( float32_t * pSrc, uint32_t blockSize, float32_t * pResult); /** * @brief Sum of the squares of the elements of a Q15 vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output value. * @return none. */ void arm_power_q15( q15_t * pSrc, uint32_t blockSize, q63_t * pResult); /** * @brief Sum of the squares of the elements of a Q7 vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output value. * @return none. */ void arm_power_q7( q7_t * pSrc, uint32_t blockSize, q31_t * pResult); /** * @brief Mean value of a Q7 vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output value. * @return none. */ void arm_mean_q7( q7_t * pSrc, uint32_t blockSize, q7_t * pResult); /** * @brief Mean value of a Q15 vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output value. * @return none. */ void arm_mean_q15( q15_t * pSrc, uint32_t blockSize, q15_t * pResult); /** * @brief Mean value of a Q31 vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output value. * @return none. */ void arm_mean_q31( q31_t * pSrc, uint32_t blockSize, q31_t * pResult); /** * @brief Mean value of a floating-point vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output value. * @return none. */ void arm_mean_f32( float32_t * pSrc, uint32_t blockSize, float32_t * pResult); /** * @brief Variance of the elements of a floating-point vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output value. * @return none. */ void arm_var_f32( float32_t * pSrc, uint32_t blockSize, float32_t * pResult); /** * @brief Variance of the elements of a Q31 vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output value. * @return none. */ void arm_var_q31( q31_t * pSrc, uint32_t blockSize, q31_t * pResult); /** * @brief Variance of the elements of a Q15 vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output value. * @return none. */ void arm_var_q15( q15_t * pSrc, uint32_t blockSize, q15_t * pResult); /** * @brief Root Mean Square of the elements of a floating-point vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output value. * @return none. */ void arm_rms_f32( float32_t * pSrc, uint32_t blockSize, float32_t * pResult); /** * @brief Root Mean Square of the elements of a Q31 vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output value. * @return none. */ void arm_rms_q31( q31_t * pSrc, uint32_t blockSize, q31_t * pResult); /** * @brief Root Mean Square of the elements of a Q15 vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output value. * @return none. */ void arm_rms_q15( q15_t * pSrc, uint32_t blockSize, q15_t * pResult); /** * @brief Standard deviation of the elements of a floating-point vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output value. * @return none. */ void arm_std_f32( float32_t * pSrc, uint32_t blockSize, float32_t * pResult); /** * @brief Standard deviation of the elements of a Q31 vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output value. * @return none. */ void arm_std_q31( q31_t * pSrc, uint32_t blockSize, q31_t * pResult); /** * @brief Standard deviation of the elements of a Q15 vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output value. * @return none. */ void arm_std_q15( q15_t * pSrc, uint32_t blockSize, q15_t * pResult); /** * @brief Floating-point complex magnitude * @param[in] *pSrc points to the complex input vector * @param[out] *pDst points to the real output vector * @param[in] numSamples number of complex samples in the input vector * @return none. */ void arm_cmplx_mag_f32( float32_t * pSrc, float32_t * pDst, uint32_t numSamples); /** * @brief Q31 complex magnitude * @param[in] *pSrc points to the complex input vector * @param[out] *pDst points to the real output vector * @param[in] numSamples number of complex samples in the input vector * @return none. */ void arm_cmplx_mag_q31( q31_t * pSrc, q31_t * pDst, uint32_t numSamples); /** * @brief Q15 complex magnitude * @param[in] *pSrc points to the complex input vector * @param[out] *pDst points to the real output vector * @param[in] numSamples number of complex samples in the input vector * @return none. */ void arm_cmplx_mag_q15( q15_t * pSrc, q15_t * pDst, uint32_t numSamples); /** * @brief Q15 complex dot product * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[in] numSamples number of complex samples in each vector * @param[out] *realResult real part of the result returned here * @param[out] *imagResult imaginary part of the result returned here * @return none. */ void arm_cmplx_dot_prod_q15( q15_t * pSrcA, q15_t * pSrcB, uint32_t numSamples, q31_t * realResult, q31_t * imagResult); /** * @brief Q31 complex dot product * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[in] numSamples number of complex samples in each vector * @param[out] *realResult real part of the result returned here * @param[out] *imagResult imaginary part of the result returned here * @return none. */ void arm_cmplx_dot_prod_q31( q31_t * pSrcA, q31_t * pSrcB, uint32_t numSamples, q63_t * realResult, q63_t * imagResult); /** * @brief Floating-point complex dot product * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[in] numSamples number of complex samples in each vector * @param[out] *realResult real part of the result returned here * @param[out] *imagResult imaginary part of the result returned here * @return none. */ void arm_cmplx_dot_prod_f32( float32_t * pSrcA, float32_t * pSrcB, uint32_t numSamples, float32_t * realResult, float32_t * imagResult); /** * @brief Q15 complex-by-real multiplication * @param[in] *pSrcCmplx points to the complex input vector * @param[in] *pSrcReal points to the real input vector * @param[out] *pCmplxDst points to the complex output vector * @param[in] numSamples number of samples in each vector * @return none. */ void arm_cmplx_mult_real_q15( q15_t * pSrcCmplx, q15_t * pSrcReal, q15_t * pCmplxDst, uint32_t numSamples); /** * @brief Q31 complex-by-real multiplication * @param[in] *pSrcCmplx points to the complex input vector * @param[in] *pSrcReal points to the real input vector * @param[out] *pCmplxDst points to the complex output vector * @param[in] numSamples number of samples in each vector * @return none. */ void arm_cmplx_mult_real_q31( q31_t * pSrcCmplx, q31_t * pSrcReal, q31_t * pCmplxDst, uint32_t numSamples); /** * @brief Floating-point complex-by-real multiplication * @param[in] *pSrcCmplx points to the complex input vector * @param[in] *pSrcReal points to the real input vector * @param[out] *pCmplxDst points to the complex output vector * @param[in] numSamples number of samples in each vector * @return none. */ void arm_cmplx_mult_real_f32( float32_t * pSrcCmplx, float32_t * pSrcReal, float32_t * pCmplxDst, uint32_t numSamples); /** * @brief Minimum value of a Q7 vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *result is output pointer * @param[in] index is the array index of the minimum value in the input buffer. * @return none. */ void arm_min_q7( q7_t * pSrc, uint32_t blockSize, q7_t * result, uint32_t * index); /** * @brief Minimum value of a Q15 vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output pointer * @param[in] *pIndex is the array index of the minimum value in the input buffer. * @return none. */ void arm_min_q15( q15_t * pSrc, uint32_t blockSize, q15_t * pResult, uint32_t * pIndex); /** * @brief Minimum value of a Q31 vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output pointer * @param[out] *pIndex is the array index of the minimum value in the input buffer. * @return none. */ void arm_min_q31( q31_t * pSrc, uint32_t blockSize, q31_t * pResult, uint32_t * pIndex); /** * @brief Minimum value of a floating-point vector. * @param[in] *pSrc is input pointer * @param[in] blockSize is the number of samples to process * @param[out] *pResult is output pointer * @param[out] *pIndex is the array index of the minimum value in the input buffer. * @return none. */ void arm_min_f32( float32_t * pSrc, uint32_t blockSize, float32_t * pResult, uint32_t * pIndex); /** * @brief Maximum value of a Q7 vector. * @param[in] *pSrc points to the input buffer * @param[in] blockSize length of the input vector * @param[out] *pResult maximum value returned here * @param[out] *pIndex index of maximum value returned here * @return none. */ void arm_max_q7( q7_t * pSrc, uint32_t blockSize, q7_t * pResult, uint32_t * pIndex); /** * @brief Maximum value of a Q15 vector. * @param[in] *pSrc points to the input buffer * @param[in] blockSize length of the input vector * @param[out] *pResult maximum value returned here * @param[out] *pIndex index of maximum value returned here * @return none. */ void arm_max_q15( q15_t * pSrc, uint32_t blockSize, q15_t * pResult, uint32_t * pIndex); /** * @brief Maximum value of a Q31 vector. * @param[in] *pSrc points to the input buffer * @param[in] blockSize length of the input vector * @param[out] *pResult maximum value returned here * @param[out] *pIndex index of maximum value returned here * @return none. */ void arm_max_q31( q31_t * pSrc, uint32_t blockSize, q31_t * pResult, uint32_t * pIndex); /** * @brief Maximum value of a floating-point vector. * @param[in] *pSrc points to the input buffer * @param[in] blockSize length of the input vector * @param[out] *pResult maximum value returned here * @param[out] *pIndex index of maximum value returned here * @return none. */ void arm_max_f32( float32_t * pSrc, uint32_t blockSize, float32_t * pResult, uint32_t * pIndex); /** * @brief Q15 complex-by-complex multiplication * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[out] *pDst points to the output vector * @param[in] numSamples number of complex samples in each vector * @return none. */ void arm_cmplx_mult_cmplx_q15( q15_t * pSrcA, q15_t * pSrcB, q15_t * pDst, uint32_t numSamples); /** * @brief Q31 complex-by-complex multiplication * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[out] *pDst points to the output vector * @param[in] numSamples number of complex samples in each vector * @return none. */ void arm_cmplx_mult_cmplx_q31( q31_t * pSrcA, q31_t * pSrcB, q31_t * pDst, uint32_t numSamples); /** * @brief Floating-point complex-by-complex multiplication * @param[in] *pSrcA points to the first input vector * @param[in] *pSrcB points to the second input vector * @param[out] *pDst points to the output vector * @param[in] numSamples number of complex samples in each vector * @return none. */ void arm_cmplx_mult_cmplx_f32( float32_t * pSrcA, float32_t * pSrcB, float32_t * pDst, uint32_t numSamples); /** * @brief Converts the elements of the floating-point vector to Q31 vector. * @param[in] *pSrc points to the floating-point input vector * @param[out] *pDst points to the Q31 output vector * @param[in] blockSize length of the input vector * @return none. */ void arm_float_to_q31( float32_t * pSrc, q31_t * pDst, uint32_t blockSize); /** * @brief Converts the elements of the floating-point vector to Q15 vector. * @param[in] *pSrc points to the floating-point input vector * @param[out] *pDst points to the Q15 output vector * @param[in] blockSize length of the input vector * @return none */ void arm_float_to_q15( float32_t * pSrc, q15_t * pDst, uint32_t blockSize); /** * @brief Converts the elements of the floating-point vector to Q7 vector. * @param[in] *pSrc points to the floating-point input vector * @param[out] *pDst points to the Q7 output vector * @param[in] blockSize length of the input vector * @return none */ void arm_float_to_q7( float32_t * pSrc, q7_t * pDst, uint32_t blockSize); /** * @brief Converts the elements of the Q31 vector to Q15 vector. * @param[in] *pSrc is input pointer * @param[out] *pDst is output pointer * @param[in] blockSize is the number of samples to process * @return none. */ void arm_q31_to_q15( q31_t * pSrc, q15_t * pDst, uint32_t blockSize); /** * @brief Converts the elements of the Q31 vector to Q7 vector. * @param[in] *pSrc is input pointer * @param[out] *pDst is output pointer * @param[in] blockSize is the number of samples to process * @return none. */ void arm_q31_to_q7( q31_t * pSrc, q7_t * pDst, uint32_t blockSize); /** * @brief Converts the elements of the Q15 vector to floating-point vector. * @param[in] *pSrc is input pointer * @param[out] *pDst is output pointer * @param[in] blockSize is the number of samples to process * @return none. */ void arm_q15_to_float( q15_t * pSrc, float32_t * pDst, uint32_t blockSize); /** * @brief Converts the elements of the Q15 vector to Q31 vector. * @param[in] *pSrc is input pointer * @param[out] *pDst is output pointer * @param[in] blockSize is the number of samples to process * @return none. */ void arm_q15_to_q31( q15_t * pSrc, q31_t * pDst, uint32_t blockSize); /** * @brief Converts the elements of the Q15 vector to Q7 vector. * @param[in] *pSrc is input pointer * @param[out] *pDst is output pointer * @param[in] blockSize is the number of samples to process * @return none. */ void arm_q15_to_q7( q15_t * pSrc, q7_t * pDst, uint32_t blockSize); /** * @ingroup groupInterpolation */ /** * @defgroup BilinearInterpolate Bilinear Interpolation * * Bilinear interpolation is an extension of linear interpolation applied to a two dimensional grid. * The underlying function <code>f(x, y)</code> is sampled on a regular grid and the interpolation process * determines values between the grid points. * Bilinear interpolation is equivalent to two step linear interpolation, first in the x-dimension and then in the y-dimension. * Bilinear interpolation is often used in image processing to rescale images. * The CMSIS DSP library provides bilinear interpolation functions for Q7, Q15, Q31, and floating-point data types. * * <b>Algorithm</b> * \par * The instance structure used by the bilinear interpolation functions describes a two dimensional data table. * For floating-point, the instance structure is defined as: * <pre> * typedef struct * { * uint16_t numRows; * uint16_t numCols; * float32_t *pData; * } arm_bilinear_interp_instance_f32; * </pre> * * \par * where <code>numRows</code> specifies the number of rows in the table; * <code>numCols</code> specifies the number of columns in the table; * and <code>pData</code> points to an array of size <code>numRows*numCols</code> values. * The data table <code>pTable</code> is organized in row order and the supplied data values fall on integer indexes. * That is, table element (x,y) is located at <code>pTable[x + y*numCols]</code> where x and y are integers. * * \par * Let <code>(x, y)</code> specify the desired interpolation point. Then define: * <pre> * XF = floor(x) * YF = floor(y) * </pre> * \par * The interpolated output point is computed as: * <pre> * f(x, y) = f(XF, YF) * (1-(x-XF)) * (1-(y-YF)) * + f(XF+1, YF) * (x-XF)*(1-(y-YF)) * + f(XF, YF+1) * (1-(x-XF))*(y-YF) * + f(XF+1, YF+1) * (x-XF)*(y-YF) * </pre> * Note that the coordinates (x, y) contain integer and fractional components. * The integer components specify which portion of the table to use while the * fractional components control the interpolation processor. * * \par * if (x,y) are outside of the table boundary, Bilinear interpolation returns zero output. */ /** * @addtogroup BilinearInterpolate * @{ */ /** * * @brief Floating-point bilinear interpolation. * @param[in,out] *S points to an instance of the interpolation structure. * @param[in] X interpolation coordinate. * @param[in] Y interpolation coordinate. * @return out interpolated value. */ static __INLINE float32_t arm_bilinear_interp_f32( const arm_bilinear_interp_instance_f32 * S, float32_t X, float32_t Y) { float32_t out; float32_t f00, f01, f10, f11; float32_t *pData = S->pData; int32_t xIndex, yIndex, index; float32_t xdiff, ydiff; float32_t b1, b2, b3, b4; xIndex = (int32_t) X; yIndex = (int32_t) Y; /* Care taken for table outside boundary */ /* Returns zero output when values are outside table boundary */ if(xIndex < 0 || xIndex > (S->numRows - 1) || yIndex < 0 || yIndex > (S->numCols - 1)) { return (0); } /* Calculation of index for two nearest points in X-direction */ index = (xIndex - 1) + (yIndex - 1) * S->numCols; /* Read two nearest points in X-direction */ f00 = pData[index]; f01 = pData[index + 1]; /* Calculation of index for two nearest points in Y-direction */ index = (xIndex - 1) + (yIndex) * S->numCols; /* Read two nearest points in Y-direction */ f10 = pData[index]; f11 = pData[index + 1]; /* Calculation of intermediate values */ b1 = f00; b2 = f01 - f00; b3 = f10 - f00; b4 = f00 - f01 - f10 + f11; /* Calculation of fractional part in X */ xdiff = X - xIndex; /* Calculation of fractional part in Y */ ydiff = Y - yIndex; /* Calculation of bi-linear interpolated output */ out = b1 + b2 * xdiff + b3 * ydiff + b4 * xdiff * ydiff; /* return to application */ return (out); } /** * * @brief Q31 bilinear interpolation. * @param[in,out] *S points to an instance of the interpolation structure. * @param[in] X interpolation coordinate in 12.20 format. * @param[in] Y interpolation coordinate in 12.20 format. * @return out interpolated value. */ static __INLINE q31_t arm_bilinear_interp_q31( arm_bilinear_interp_instance_q31 * S, q31_t X, q31_t Y) { q31_t out; /* Temporary output */ q31_t acc = 0; /* output */ q31_t xfract, yfract; /* X, Y fractional parts */ q31_t x1, x2, y1, y2; /* Nearest output values */ int32_t rI, cI; /* Row and column indices */ q31_t *pYData = S->pData; /* pointer to output table values */ uint32_t nCols = S->numCols; /* num of rows */ /* Input is in 12.20 format */ /* 12 bits for the table index */ /* Index value calculation */ rI = ((X & 0xFFF00000) >> 20u); /* Input is in 12.20 format */ /* 12 bits for the table index */ /* Index value calculation */ cI = ((Y & 0xFFF00000) >> 20u); /* Care taken for table outside boundary */ /* Returns zero output when values are outside table boundary */ if(rI < 0 || rI > (S->numRows - 1) || cI < 0 || cI > (S->numCols - 1)) { return (0); } /* 20 bits for the fractional part */ /* shift left xfract by 11 to keep 1.31 format */ xfract = (X & 0x000FFFFF) << 11u; /* Read two nearest output values from the index */ x1 = pYData[(rI) + nCols * (cI)]; x2 = pYData[(rI) + nCols * (cI) + 1u]; /* 20 bits for the fractional part */ /* shift left yfract by 11 to keep 1.31 format */ yfract = (Y & 0x000FFFFF) << 11u; /* Read two nearest output values from the index */ y1 = pYData[(rI) + nCols * (cI + 1)]; y2 = pYData[(rI) + nCols * (cI + 1) + 1u]; /* Calculation of x1 * (1-xfract ) * (1-yfract) and acc is in 3.29(q29) format */ out = ((q31_t) (((q63_t) x1 * (0x7FFFFFFF - xfract)) >> 32)); acc = ((q31_t) (((q63_t) out * (0x7FFFFFFF - yfract)) >> 32)); /* x2 * (xfract) * (1-yfract) in 3.29(q29) and adding to acc */ out = ((q31_t) ((q63_t) x2 * (0x7FFFFFFF - yfract) >> 32)); acc += ((q31_t) ((q63_t) out * (xfract) >> 32)); /* y1 * (1 - xfract) * (yfract) in 3.29(q29) and adding to acc */ out = ((q31_t) ((q63_t) y1 * (0x7FFFFFFF - xfract) >> 32)); acc += ((q31_t) ((q63_t) out * (yfract) >> 32)); /* y2 * (xfract) * (yfract) in 3.29(q29) and adding to acc */ out = ((q31_t) ((q63_t) y2 * (xfract) >> 32)); acc += ((q31_t) ((q63_t) out * (yfract) >> 32)); /* Convert acc to 1.31(q31) format */ return (acc << 2u); } /** * @brief Q15 bilinear interpolation. * @param[in,out] *S points to an instance of the interpolation structure. * @param[in] X interpolation coordinate in 12.20 format. * @param[in] Y interpolation coordinate in 12.20 format. * @return out interpolated value. */ static __INLINE q15_t arm_bilinear_interp_q15( arm_bilinear_interp_instance_q15 * S, q31_t X, q31_t Y) { q63_t acc = 0; /* output */ q31_t out; /* Temporary output */ q15_t x1, x2, y1, y2; /* Nearest output values */ q31_t xfract, yfract; /* X, Y fractional parts */ int32_t rI, cI; /* Row and column indices */ q15_t *pYData = S->pData; /* pointer to output table values */ uint32_t nCols = S->numCols; /* num of rows */ /* Input is in 12.20 format */ /* 12 bits for the table index */ /* Index value calculation */ rI = ((X & 0xFFF00000) >> 20); /* Input is in 12.20 format */ /* 12 bits for the table index */ /* Index value calculation */ cI = ((Y & 0xFFF00000) >> 20); /* Care taken for table outside boundary */ /* Returns zero output when values are outside table boundary */ if(rI < 0 || rI > (S->numRows - 1) || cI < 0 || cI > (S->numCols - 1)) { return (0); } /* 20 bits for the fractional part */ /* xfract should be in 12.20 format */ xfract = (X & 0x000FFFFF); /* Read two nearest output values from the index */ x1 = pYData[(rI) + nCols * (cI)]; x2 = pYData[(rI) + nCols * (cI) + 1u]; /* 20 bits for the fractional part */ /* yfract should be in 12.20 format */ yfract = (Y & 0x000FFFFF); /* Read two nearest output values from the index */ y1 = pYData[(rI) + nCols * (cI + 1)]; y2 = pYData[(rI) + nCols * (cI + 1) + 1u]; /* Calculation of x1 * (1-xfract ) * (1-yfract) and acc is in 13.51 format */ /* x1 is in 1.15(q15), xfract in 12.20 format and out is in 13.35 format */ /* convert 13.35 to 13.31 by right shifting and out is in 1.31 */ out = (q31_t) (((q63_t) x1 * (0xFFFFF - xfract)) >> 4u); acc = ((q63_t) out * (0xFFFFF - yfract)); /* x2 * (xfract) * (1-yfract) in 1.51 and adding to acc */ out = (q31_t) (((q63_t) x2 * (0xFFFFF - yfract)) >> 4u); acc += ((q63_t) out * (xfract)); /* y1 * (1 - xfract) * (yfract) in 1.51 and adding to acc */ out = (q31_t) (((q63_t) y1 * (0xFFFFF - xfract)) >> 4u); acc += ((q63_t) out * (yfract)); /* y2 * (xfract) * (yfract) in 1.51 and adding to acc */ out = (q31_t) (((q63_t) y2 * (xfract)) >> 4u); acc += ((q63_t) out * (yfract)); /* acc is in 13.51 format and down shift acc by 36 times */ /* Convert out to 1.15 format */ return (acc >> 36); } /** * @brief Q7 bilinear interpolation. * @param[in,out] *S points to an instance of the interpolation structure. * @param[in] X interpolation coordinate in 12.20 format. * @param[in] Y interpolation coordinate in 12.20 format. * @return out interpolated value. */ static __INLINE q7_t arm_bilinear_interp_q7( arm_bilinear_interp_instance_q7 * S, q31_t X, q31_t Y) { q63_t acc = 0; /* output */ q31_t out; /* Temporary output */ q31_t xfract, yfract; /* X, Y fractional parts */ q7_t x1, x2, y1, y2; /* Nearest output values */ int32_t rI, cI; /* Row and column indices */ q7_t *pYData = S->pData; /* pointer to output table values */ uint32_t nCols = S->numCols; /* num of rows */ /* Input is in 12.20 format */ /* 12 bits for the table index */ /* Index value calculation */ rI = ((X & 0xFFF00000) >> 20); /* Input is in 12.20 format */ /* 12 bits for the table index */ /* Index value calculation */ cI = ((Y & 0xFFF00000) >> 20); /* Care taken for table outside boundary */ /* Returns zero output when values are outside table boundary */ if(rI < 0 || rI > (S->numRows - 1) || cI < 0 || cI > (S->numCols - 1)) { return (0); } /* 20 bits for the fractional part */ /* xfract should be in 12.20 format */ xfract = (X & 0x000FFFFF); /* Read two nearest output values from the index */ x1 = pYData[(rI) + nCols * (cI)]; x2 = pYData[(rI) + nCols * (cI) + 1u]; /* 20 bits for the fractional part */ /* yfract should be in 12.20 format */ yfract = (Y & 0x000FFFFF); /* Read two nearest output values from the index */ y1 = pYData[(rI) + nCols * (cI + 1)]; y2 = pYData[(rI) + nCols * (cI + 1) + 1u]; /* Calculation of x1 * (1-xfract ) * (1-yfract) and acc is in 16.47 format */ out = ((x1 * (0xFFFFF - xfract))); acc = (((q63_t) out * (0xFFFFF - yfract))); /* x2 * (xfract) * (1-yfract) in 2.22 and adding to acc */ out = ((x2 * (0xFFFFF - yfract))); acc += (((q63_t) out * (xfract))); /* y1 * (1 - xfract) * (yfract) in 2.22 and adding to acc */ out = ((y1 * (0xFFFFF - xfract))); acc += (((q63_t) out * (yfract))); /* y2 * (xfract) * (yfract) in 2.22 and adding to acc */ out = ((y2 * (yfract))); acc += (((q63_t) out * (xfract))); /* acc in 16.47 format and down shift by 40 to convert to 1.7 format */ return (acc >> 40); } /** * @} end of BilinearInterpolate group */ //SMMLAR #define multAcc_32x32_keep32_R(a, x, y) \ a = (q31_t) (((((q63_t) a) << 32) + ((q63_t) x * y) + 0x80000000LL ) >> 32) //SMMLSR #define multSub_32x32_keep32_R(a, x, y) \ a = (q31_t) (((((q63_t) a) << 32) - ((q63_t) x * y) + 0x80000000LL ) >> 32) //SMMULR #define mult_32x32_keep32_R(a, x, y) \ a = (q31_t) (((q63_t) x * y + 0x80000000LL ) >> 32) //SMMLA #define multAcc_32x32_keep32(a, x, y) \ a += (q31_t) (((q63_t) x * y) >> 32) //SMMLS #define multSub_32x32_keep32(a, x, y) \ a -= (q31_t) (((q63_t) x * y) >> 32) //SMMUL #define mult_32x32_keep32(a, x, y) \ a = (q31_t) (((q63_t) x * y ) >> 32) #if defined ( __CC_ARM ) //Keil //Enter low optimization region - place directly above function definition #ifdef ARM_MATH_CM4 #define LOW_OPTIMIZATION_ENTER \ _Pragma ("push") \ _Pragma ("O1") #else #define LOW_OPTIMIZATION_ENTER #endif //Exit low optimization region - place directly after end of function definition #ifdef ARM_MATH_CM4 #define LOW_OPTIMIZATION_EXIT \ _Pragma ("pop") #else #define LOW_OPTIMIZATION_EXIT #endif //Enter low optimization region - place directly above function definition #define IAR_ONLY_LOW_OPTIMIZATION_ENTER //Exit low optimization region - place directly after end of function definition #define IAR_ONLY_LOW_OPTIMIZATION_EXIT #elif defined(__ICCARM__) //IAR //Enter low optimization region - place directly above function definition #ifdef ARM_MATH_CM4 #define LOW_OPTIMIZATION_ENTER \ _Pragma ("optimize=low") #else #define LOW_OPTIMIZATION_ENTER #endif //Exit low optimization region - place directly after end of function definition #define LOW_OPTIMIZATION_EXIT //Enter low optimization region - place directly above function definition #ifdef ARM_MATH_CM4 #define IAR_ONLY_LOW_OPTIMIZATION_ENTER \ _Pragma ("optimize=low") #else #define IAR_ONLY_LOW_OPTIMIZATION_ENTER #endif //Exit low optimization region - place directly after end of function definition #define IAR_ONLY_LOW_OPTIMIZATION_EXIT #elif defined(__GNUC__) #define LOW_OPTIMIZATION_ENTER __attribute__(( optimize("-O1") )) #define LOW_OPTIMIZATION_EXIT #define IAR_ONLY_LOW_OPTIMIZATION_ENTER #define IAR_ONLY_LOW_OPTIMIZATION_EXIT #elif defined(__CSMC__) // Cosmic #define LOW_OPTIMIZATION_ENTER #define LOW_OPTIMIZATION_EXIT #define IAR_ONLY_LOW_OPTIMIZATION_ENTER #define IAR_ONLY_LOW_OPTIMIZATION_EXIT #elif defined(__TASKING__) // TASKING #define LOW_OPTIMIZATION_ENTER #define LOW_OPTIMIZATION_EXIT #define IAR_ONLY_LOW_OPTIMIZATION_ENTER #define IAR_ONLY_LOW_OPTIMIZATION_EXIT #endif #ifdef __cplusplus } #endif #endif /* _ARM_MATH_H */ /** * * End of file. */