CMSIS-DSP: Added scalar f32 quaternion functions.
Some correction for RFFT Fast f32 in Python wrapper
diff --git a/CMSIS/DSP/cmsisdspconfig.py b/CMSIS/DSP/cmsisdspconfig.py
new file mode 100755
index 0000000..71c21c2
--- /dev/null
+++ b/CMSIS/DSP/cmsisdspconfig.py
@@ -0,0 +1,581 @@
+# Web UI for configuration of the CMSIS-DSP Build
+#
+# How to install
+# pip install streamlit
+#
+# How to use
+# streamlit run cmsisconfig.py
+#
+import streamlit as st
+import textwrap
+import re
+
+
+st.set_page_config(page_title="CMSIS-DSP Configuration",layout="wide" )
+
+# Options requiring a special management
+NOTSTANDARD=["allTables","allInterpolations","allFFTs","Float16"]
+
+HELIUM=False
+
+config={}
+
+config["allTables"] = True
+config["allFFTs"] = True
+config["allInterpolations"] = True
+config["MVEI"]=False
+config["MVEF"]=False
+config["NEON"]=False
+config["HELIUM"]=False
+config["Float16"]=True
+config["HOST"]=False
+
+config["COS_F32"]=False
+config["COS_Q31"]=False
+config["COS_Q15"]=False
+config["SIN_F32"]=False
+config["SIN_Q31"]=False
+config["SIN_Q15"]=False
+config["SIN_COS_F32"]=False
+config["SIN_COS_Q31"]=False
+config["LMS_NORM_Q31"]=False
+config["LMS_NORM_Q15"]=False
+config["CMPLX_MAG_Q31"]=False
+config["CMPLX_MAG_Q15"]=False
+
+config["BASICMATH"]=True  
+config["COMPLEXMATH"]=True
+config["CONTROLLER"]=True    
+config["FASTMATH"]=True      
+config["FILTERING"]=True     
+config["MATRIX"]=True       
+config["STATISTICS"]=True    
+config["SUPPORT"]=True       
+config["TRANSFORM"]=True   
+config["SVM"]=True           
+config["BAYES"]=True        
+config["DISTANCE"]=True     
+config["INTERPOLATION"]=True
+config["QUATERNIONMATH"]=True
+
+config["LOOPUNROLL"]=True
+config["ROUNDING"]=False
+config["MATRIXCHECK"]=False
+config["AUTOVECTORIZE"] = False
+
+realname={}
+realname["COS_F32"]="ARM_COS_F32"
+realname["COS_Q31"]="ARM_COS_Q31"
+realname["COS_Q15"]="ARM_COS_Q15"
+realname["SIN_F32"]="ARM_SIN_F32"
+realname["SIN_Q31"]="ARM_SIN_Q31"
+realname["SIN_Q15"]="ARM_SIN_Q15"
+realname["SIN_COS_F32"]="ARM_SIN_COS_F32"
+realname["SIN_COS_Q31"]="ARM_SIN_COS_Q31"
+realname["LMS_NORM_Q31"]="ARM_LMS_NORM_Q31"
+realname["LMS_NORM_Q15"]="ARM_LMS_NORM_Q15"
+realname["CMPLX_MAG_Q31"]="ARM_CMPLX_MAG_Q31"
+realname["CMPLX_MAG_Q15"]="ARM_CMPLX_MAG_Q15"
+
+defaulton={}
+defaulton["LOOPUNROLL"]=True 
+defaulton["BASICMATH"]=True  
+defaulton["COMPLEXMATH"]=True
+defaulton["CONTROLLER"]=True   
+defaulton["FASTMATH"]=True     
+defaulton["FILTERING"]=True    
+defaulton["MATRIX"]=True       
+defaulton["STATISTICS"]=True   
+defaulton["SUPPORT"]=True      
+defaulton["TRANSFORM"]=True   
+defaulton["SVM"]=True          
+defaulton["BAYES"]=True        
+defaulton["DISTANCE"]=True     
+defaulton["INTERPOLATION"]=True
+defaulton["QUATERNIONMATH"]=True
+
+
+CFFTSIZE=[16,32,64,128,256,512,1024,2048,4096]
+CFFTDATATYPE=['F64','F32','F16','Q31','Q15']
+
+RFFTFASTSIZE=[32,64,128,256,512,1024,2048,4096]
+RFFTFASTDATATYPE=['F64','F32','F16']
+
+RFFTSIZE=[32,64,128,256,512,1024,2048,4096,8192]
+RFFTDATATYPE=['F32','Q31','Q15']
+
+DCTSIZE=[128,512,2048,8192]
+DCTDATATYPE=['F32','Q31','Q15']
+
+def joinit(iterable, delimiter):
+    # Intersperse a delimiter between element of a list
+    it = iter(iterable)
+    yield next(it)
+    for x in it:
+        yield delimiter
+        yield x
+
+def options(l):
+    return("".join(joinit(l," ")))
+
+def computeCmakeOptions(config):
+    global defaulton
+    cmake={}
+    if not config["allTables"]:
+       cmake["CONFIGTABLE"]=True
+       if config["allInterpolations"]:
+          cmake["ALLFAST"]=True
+       if config["allFFTs"]:
+          cmake["ALLFFT"]=True
+    if config["Float16"]:
+       cmake["FLOAT16"]=True
+    else:
+       cmake["DISABLEFLOAT16"]=True
+
+    for c in config:
+        if not (c in NOTSTANDARD):
+           if c in defaulton:
+                if not config[c]:
+                   if c in realname:
+                      cmake[realname[c]]=False
+                   else:
+                      cmake[c]=False
+           else:
+                if config[c]:
+                   if c in realname:
+                      cmake[realname[c]]=True
+                   else:
+                      cmake[c]=True
+    return cmake 
+
+def removeDuplicates(l):
+  return list(dict.fromkeys(l))
+
+def genCMakeOptions(config):
+    r=[]
+    cmake = computeCmakeOptions(config)
+    for c in cmake:
+        if cmake[c]:
+           r.append("-D%s=ON" % c)
+        else:
+           r.append("-D%s=OFF" % c)
+    return(removeDuplicates(r),cmake)
+
+def test(cmake,s):
+    global defaulton
+    if s in defaulton and not (s in cmake):
+       return True 
+    return(s in cmake and cmake[s])
+
+def cfftCF32Config(cmake,size):
+    result=[]
+    if test(cmake,"CFFT_F32_%d" % size):
+       a="-DARM_TABLE_TWIDDLECOEF_F32_%d" % size
+       if HELIUM:
+          b = "-DARM_TABLE_BITREVIDX_FXT_%d" % size
+       else:
+          b = "-DARM_TABLE_BITREVIDX_FLT_%d" % size 
+       result=[a,b]
+    return(result)
+
+def cfftCF16Config(cmake,size):
+    result=[]
+    if test(cmake,"CFFT_F16_%d" % size):
+       result =["-DARM_TABLE_TWIDDLECOEF_F16_%d" % size]
+       result.append("-DARM_TABLE_BITREVIDX_FXT_%d" % size)
+       result.append("-DARM_TABLE_BITREVIDX_FLT_%d" % size)
+    return(result)
+
+def cfftCF64Config(cmake,size):
+    result=[]
+    if test(cmake,"CFFT_F64_%d" % size):
+       result =["-DARM_TABLE_TWIDDLECOEF_F64_%d" % size]
+       result.append("-DARM_TABLE_BITREVIDX_FLT64_%d" % size)
+    return(result)
+
+
+def cfftCFixedConfig(cmake,dt,size):
+    result=[]
+    if test(cmake,"CFFT_%s_%d" % (dt,size)):
+       a="-DARM_TABLE_TWIDDLECOEF_%s_%d" % (dt,size)
+       b = "-DARM_TABLE_BITREVIDX_FXT_%d" % size
+       result=[a,b]
+    return(result)
+
+def crfftFastCF64Config(cmake,size):
+    result=[]
+    s1 = size >> 1
+    if test(cmake,"RFFT_FAST_F64_%d" % size):
+       result =[]
+       result.append("-DARM_TABLE_TWIDDLECOEF_F64_%d" % s1)
+       result.append("-DARM_TABLE_BITREVIDX_FLT64_%d" % s1)
+       result.append("-DARM_TABLE_TWIDDLECOEF_RFFT_F64_%d" % size)
+       result.append("-DARM_TABLE_TWIDDLECOEF_F64_%d" % s1)
+       
+    return(result)
+
+def crfftFastCF32Config(cmake,size):
+    result=[]
+    s1 = size >> 1
+    if test(cmake,"RFFT_FAST_F32_%d" % size):
+       result =[]
+       result.append("-DARM_TABLE_TWIDDLECOEF_F32_%d" % s1)
+       result.append("-DARM_TABLE_BITREVIDX_FLT_%d" % s1)
+       result.append("-DARM_TABLE_TWIDDLECOEF_RFFT_F32_%d" % size)
+       
+    return(result)
+
+def crfftFastCF16Config(cmake,size):
+    result=[]
+    s1 = size >> 1
+    if test(cmake,"RFFT_FAST_F16_%d" % size):
+       result =[]
+       result.append("-DARM_TABLE_TWIDDLECOEF_F16_%d" % s1)
+       result.append("-DARM_TABLE_BITREVIDX_FLT_%d" % s1)
+       result.append("-DARM_TABLE_BITREVIDX_FXT_%d" % s1)
+       result.append("-DARM_TABLE_TWIDDLECOEF_RFFT_F16_%d" % size)
+       
+    return(result)
+
+# Deprecated RFFT used in DCT
+def crfftF32Config(cmake,size):
+    result=[]
+    s1 = size >> 1
+    if test(cmake,"RFFT_FAST_F16_%d" % size):
+       result =[]
+       result.append("-DARM_TABLE_REALCOEF_F32")
+       result.append("-ARM_TABLE_BITREV_%d" % s1)
+       result.append("-ARM_TABLE_TWIDDLECOEF_F32_%d" % s1)
+       
+    return(result)
+
+
+def crfftFixedConfig(cmake,dt,size):
+    result=[]
+    s1 = size >> 1
+    if test(cmake,"RFFT_%s_%d" % (dt,size)):
+       result =[]
+       result.append("-DARM_TABLE_REALCOEF_%s" % dt)
+       result.append("-DARM_TABLE_TWIDDLECOEF_%s_%d" % (dt,s1))
+       result.append("-DARM_TABLE_BITREVIDX_FXT_%d" % s1)
+       
+    return(result)
+
+
+def dctConfig(cmake,dt,size):
+    result=[]
+    if test(cmake,"DCT4_%s_%d" % (dt,size)):
+       result =[]
+       result.append("-DARM_TABLE_DCT4_%s_%d" % (dt,size))
+       result.append("-DARM_TABLE_REALCOEF_F32")
+       result.append("-DARM_TABLE_BITREV_1024" )
+       result.append("-DARM_TABLE_TWIDDLECOEF_%s_4096" % dt)
+       
+    return(result)
+
+# Convert cmake options to make flags
+def interpretCmakeOptions(cmake):
+    r=[]
+    if test(cmake,"CONFIGTABLE"):
+       r.append("-DARM_DSP_CONFIG_TABLES")
+       # In Make configuration we build all modules.
+       # So the code for FFT and FAST maths may be included
+       # so we allow the table to be included if they are needed.
+       r.append("-DARM_FAST_ALLOW_TABLES")
+       r.append("-DARM_FFT_ALLOW_TABLES")
+       for size in CFFTSIZE:
+           r += cfftCF32Config(cmake,size)
+           r += cfftCF16Config(cmake,size)
+           r += cfftCF64Config(cmake,size)
+           r += cfftCFixedConfig(cmake,"Q31",size)
+           r += cfftCFixedConfig(cmake,"Q15",size)
+
+       for size in RFFTFASTSIZE:
+          r += crfftFastCF64Config(cmake,size)
+          r += crfftFastCF32Config(cmake,size)
+          r += crfftFastCF16Config(cmake,size)
+
+       for size in RFFTSIZE:
+          r += crfftFixedConfig(cmake,"F32",size)
+          r += crfftFixedConfig(cmake,"Q31",size)
+          r += crfftFixedConfig(cmake,"Q15",size)
+
+       for size in DCTSIZE:
+          r += dctConfig(cmake,"F32",size)
+          r += dctConfig(cmake,"Q31",size)
+          r += dctConfig(cmake,"Q15",size)
+
+        
+    
+    if test(cmake,"ALLFAST"):
+       r.append("-DARM_ALL_FAST_TABLES")
+    if test(cmake,"ALLFFT"):
+       r.append("-DARM_ALL_FFT_TABLES")
+
+    if test(cmake,"LOOPUNROLL"):
+       r.append("-DARM_MATH_LOOPUNROLL")
+    if test(cmake,"ROUNDING"):
+       r.append("-DARM_MATH_ROUNDING")
+    if test(cmake,"MATRIXCHECK"):
+       r.append("-DARM_MATH_MATRIX_CHECK")
+    if test(cmake,"AUTOVECTORIZE"):
+       r.append("-DARM_MATH_AUTOVECTORIZE")
+    if test(cmake,"DISABLEFLOAT16"):
+       r.append("-DDISABLEFLOAT16")
+    if test(cmake,"NEON"):
+       r.append("-DARM_MATH_NEON")
+       r.append("-DARM_MATH_NEON_EXPERIMENTAL")
+    if test(cmake,"HOST"):
+        r.append("-D__GNUC_PYTHON__")
+    
+    if test(cmake,"ARM_COS_F32"):
+        r.append("-DARM_TABLE_SIN_F32")
+    if test(cmake,"ARM_COS_Q31"):
+        r.append("-DARM_TABLE_SIN_Q31")
+    if test(cmake,"ARM_COS_Q15"):
+        r.append("-DARM_TABLE_SIN_Q15")
+
+    if test(cmake,"ARM_SIN_F32"):
+        r.append("-DARM_TABLE_SIN_F32")
+    if test(cmake,"ARM_SIN_Q31"):
+        r.append("-DARM_TABLE_SIN_Q31")
+    if test(cmake,"ARM_SIN_Q15"):
+        r.append("-DARM_TABLE_SIN_Q15")
+
+    if test(cmake,"ARM_SIN_COS_F32"):
+        r.append("-DARM_TABLE_SIN_F32")
+    if test(cmake,"ARM_SIN_COS_Q31"):
+        r.append("-DARM_TABLE_SIN_Q31")
+
+    if test(cmake,"ARM_LMS_NORM_Q31"):
+        r.append("-DARM_TABLE_RECIP_Q31")
+
+    if test(cmake,"ARM_LMS_NORM_Q15"):
+        r.append("-DARM_TABLE_RECIP_Q15")
+
+    if test(cmake,"ARM_CMPLX_MAG_Q31"):
+        r.append("-DARM_TABLE_FAST_SQRT_Q31_MVE")
+
+    if test(cmake,"ARM_CMPLX_MAG_Q15"):
+        r.append("-DARM_TABLE_FAST_SQRT_Q15_MVE")
+
+    if test(cmake,"MVEI"):
+       r.append("-DARM_MATH_MVEI")
+
+    if test(cmake,"MVEF"):
+       r.append("-DARM_MATH_MVEF")
+
+    if test(cmake,"HELIUM") or test(cmake,"MVEF") or test(cmake,"MVEI"):
+       r.append("-IPrivateInclude")
+
+    if test(cmake,"NEON") or test(cmake,"NEONEXPERIMENTAL"):
+       r.append("-IComputeLibrary/Include")
+
+    return (removeDuplicates(r))
+
+def genMakeOptions(config):
+    cmake = computeCmakeOptions(config)
+    r=interpretCmakeOptions(cmake)
+    return(r,cmake)
+
+
+def check(config,s,name=None,comment=None):
+    if comment is not None:
+       st.sidebar.text(comment)
+    if name is None:
+       config[s]=st.sidebar.checkbox(s,value=config[s])
+    else:
+       config[s]=st.sidebar.checkbox(name,value=config[s])
+    return(config[s])
+
+def genconfig(config,transform,sizes,datatypes):
+    global realname
+    for size in sizes:
+        for dt in datatypes:
+            s="%s_%s_%s" % (transform,dt,size)
+            config[s] = False
+            realname[s] = s
+
+def hasDCTF32(config):
+    result=False
+    for size in DCTSIZE:
+            s="DCT4_F32_%s" % size
+            if config[s]:
+               result = True
+    return(result)
+
+def multiselect(config,name,options):
+    default=[]
+    for r in options:
+        if config[r]:
+            default.append(r)
+    result=st.sidebar.multiselect(name,options,default=default)
+    for r in options:
+        config[r] = False
+    for r in result:
+        config[r] = True
+
+def genui(config,transform,sizes,datatypes):
+    keepF32 = True
+    # RFFT F32 is deprecated and needed only for DCT4
+    if transform == "RFFT":
+       keepF32 = hasDCTF32(config)
+    selected=st.sidebar.multiselect("Sizes",sizes)
+    for size in selected:
+        options=[]
+        for dt in datatypes:
+            if dt != "F32" or keepF32:
+               s="%s_%s_%s" % (transform,dt,size)
+               options.append(s)
+        multiselect(config,"Nb = %d" % size,options)
+
+
+def configMake(config):
+    st.sidebar.header('Table Configuration')
+    st.sidebar.info("Several options to include only the tables needed in an app and minimize code size.")
+    if not check(config,"allTables","All tables included"):
+
+        if not check(config,"allFFTs","All FFT tables included"):
+           st.sidebar.markdown("#### CFFT")
+           genui(config,"CFFT",CFFTSIZE,CFFTDATATYPE)
+
+           st.sidebar.info("Following transforms are using the CFFT. You need to enable the needed CFFTs above.")
+
+           st.sidebar.markdown("#### RFFT FAST")
+           genui(config,"RFFT_FAST",RFFTFASTSIZE,RFFTFASTDATATYPE)
+           st.sidebar.markdown("#### DCT4")
+           genui(config,"DCT4",DCTSIZE,DCTDATATYPE)
+           st.sidebar.markdown("#### RFFT")
+           genui(config,"RFFT",RFFTSIZE,RFFTDATATYPE)
+           
+
+
+
+        if not check(config,"allInterpolations",'All interpolation tables included'):
+           selected=st.sidebar.multiselect("Functions",["Cosine","Sine","SineCosine","Normalized LMS"])
+           for s in selected:
+               if s == "Cosine":
+                  multiselect(config,"Cosine",["COS_F32","COS_Q31","COS_Q15"])
+               if s == "Sine":
+                  multiselect(config,"Sine",["SIN_F32","SIN_Q31","SIN_Q15"])
+               if s == "SineCosine":
+                  multiselect(config,"SineCosine",["SIN_COS_F32","SIN_COS_Q31"])
+               if s == "Normalized LMS":
+                  multiselect(config,"Normalized LMS",["LMS_NORM_Q31","LMS_NORM_Q15"])
+
+           if config["MVEI"]:
+              st.sidebar.markdown("#### Complex Magnitude")
+              multiselect(config,"Complex Magnitude",["CMPLX_MAG_Q31","CMPLX_MAG_Q15"])
+
+
+
+def configCMake(config):
+    multiselect(config,"Folders",["BASICMATH",     
+                       "COMPLEXMATH",   
+                       "CONTROLLER",    
+                       "FASTMATH",      
+                       "FILTERING",     
+                       "MATRIX",        
+                       "STATISTICS",    
+                       "SUPPORT",       
+                       "TRANSFORM",     
+                       "SVM",           
+                       "BAYES",         
+                       "DISTANCE",      
+                       "INTERPOLATION","QUATERNIONMATH"])  
+    configMake(config)
+
+genconfig(config,"CFFT",CFFTSIZE,CFFTDATATYPE)
+genconfig(config,"RFFT_FAST",RFFTFASTSIZE,RFFTFASTDATATYPE)
+genconfig(config,"RFFT",RFFTSIZE,RFFTDATATYPE)
+genconfig(config,"DCT4",DCTSIZE,DCTDATATYPE)
+
+st.title('CMSIS-DSP Configuration')
+
+st.warning("It is a work in progress. Only a small subset of the combinations has been tested.")
+
+st.sidebar.header('Feature Configuration')
+st.sidebar.info("To build on host. All features will be enabled.")
+forHost=check(config,"HOST")
+
+if not forHost:
+   st.sidebar.info("Enable or disable float16 support")
+   check(config,"Float16")
+
+   st.sidebar.info("Some configurations for the CMSIS-DSP code.")
+   check(config,"LOOPUNROLL")
+   st.sidebar.text("Decrease performances when selected:")
+   check(config,"ROUNDING")
+   check(config,"MATRIXCHECK")
+   
+   st.sidebar.info("Enable vector code. It is not automatic for Neon. Use of Helium will enable new options to select some interpolation tables.")
+   archi=st.sidebar.selectbox("Vector",('None','Helium','Neon'))
+   if archi == 'Neon':
+       config["NEON"]=True
+   if archi == 'Helium':
+      multiselect(config,"MVE configuration",["MVEI","MVEF"])
+      HELIUM=True
+   if archi != 'None':
+       st.sidebar.info("When autovectorization is on, pure C code will be compiled. The version with C intrinsics won't be compiled.")
+       check(config,"AUTOVECTORIZE")
+
+
+
+st.sidebar.header('Build Method')
+
+st.sidebar.info("With cmake, some folders can be removed from the build.")
+selected=st.sidebar.selectbox('Select', ("Make","Cmake"),index=1)
+
+
+
+if selected == "Make":
+    if not forHost:
+       configMake(config)
+    result,cmake=genMakeOptions(config)
+else:
+    if not forHost:
+       configCMake(config)
+    result,cmake=genCMakeOptions(config)
+
+st.header('Build options for %s command line' % selected)
+
+if selected == "Make":
+    if test(cmake,"FLOAT16"):
+            st.info("Float16 is selected. You may need to pass compiler specific options for the compiler to recognize the float16 type.")
+
+mode=st.selectbox("Mode",["txt","MDK","sh","bat"])
+
+if mode=="txt":
+   st.code(textwrap.fill(options(result)))
+
+if mode=="MDK":
+   opts=options(result)
+   includes=""
+   maybeincludes=re.findall(r'\-I([^\s]+)',opts)
+   # Managed in MDK pack file
+   #if maybeincludes:
+   #   includes = maybeincludes
+   #   st.text("Following include directories must be added")
+   #   st.code(includes)
+   opts=re.sub(r'\-D','',opts)
+   opts=re.sub(r'\-I[^\s]+','',opts)
+   st.text("MDK Preprocessor Symbols ")
+   st.code(opts)
+
+
+if mode=="sh":
+   lines=options(result).split() 
+   txt=""
+   for l in lines:
+       txt += " %s \\\n" % l
+   txt += "\n"
+   st.code(txt)
+
+if mode=="bat":
+   lines=options(result).split() 
+   txt=""
+   for l in lines:
+       txt += " %s ^\n" % l
+   txt += "\n"
+   st.code(txt)
+