/*********************************************************************************************************************** PicoMite MMBasic MATHS.c Geoff Graham, Peter Mather Copyright (c) 2021, All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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. 3. The name MMBasic be used when referring to the interpreter in any documentation and promotional material and the original copyright message be displayed on the console at startup (additional copyright messages may be added). 4. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed by the . 5. Neither the name of the 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 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 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. ************************************************************************************************************************/ /** * @file MATHS.c * @author Geoff Graham, Peter Mather * @brief Source for MATHS MMBasic commands and functions */ /** * @cond * The following section will be excluded from the documentation. */ #include "MMBasic_Includes.h" #include "Hardware_Includes.h" #include #include #ifdef rp2350 #include "pico/rand.h" #endif #define CBC 1 #define CTR 1 #define ECB 1 #include "aes.h" MMFLOAT PI; typedef MMFLOAT complex cplx; typedef float complex fcplx; void cmd_FFT(unsigned char *pp); const MMFLOAT chitable[51][15]={ {0.995,0.99,0.975,0.95,0.9,0.5,0.2,0.1,0.05,0.025,0.02,0.01,0.005,0.002,0.001}, {0.0000397,0.000157,0.000982,0.00393,0.0158,0.455,1.642,2.706,3.841,5.024,5.412,6.635,7.879,9.550,10.828}, {0.0100,0.020,0.051,0.103,0.211,1.386,3.219,4.605,5.991,7.378,7.824,9.210,10.597,12.429,13.816}, {0.072,0.115,0.216,0.352,0.584,2.366,4.642,6.251,7.815,9.348,9.837,11.345,12.838,14.796,16.266}, {0.207,0.297,0.484,0.711,1.064,3.357,5.989,7.779,9.488,11.143,11.668,13.277,14.860,16.924,18.467}, {0.412,0.554,0.831,1.145,1.610,4.351,7.289,9.236,11.070,12.833,13.388,15.086,16.750,18.907,20.515}, {0.676,0.872,1.237,1.635,2.204,5.348,8.558,10.645,12.592,14.449,15.033,16.812,18.548,20.791,22.458}, {0.989,1.239,1.690,2.167,2.833,6.346,9.803,12.017,14.067,16.013,16.622,18.475,20.278,22.601,24.322}, {1.344,1.646,2.180,2.733,3.490,7.344,11.030,13.362,15.507,17.535,18.168,20.090,21.955,24.352,26.124}, {1.735,2.088,2.700,3.325,4.168,8.343,12.242,14.684,16.919,19.023,19.679,21.666,23.589,26.056,27.877}, {2.156,2.558,3.247,3.940,4.865,9.342,13.442,15.987,18.307,20.483,21.161,23.209,25.188,27.722,29.588}, {2.603,3.053,3.816,4.575,5.578,10.341,14.631,17.275,19.675,21.920,22.618,24.725,26.757,29.354,31.264}, {3.074,3.571,4.404,5.226,6.304,11.340,15.812,18.549,21.026,23.337,24.054,26.217,28.300,30.957,32.909}, {3.565,4.107,5.009,5.892,7.042,12.340,16.985,19.812,22.362,24.736,25.472,27.688,29.819,32.535,34.528}, {4.075,4.660,5.629,6.571,7.790,13.339,18.151,21.064,23.685,26.119,26.873,29.141,31.319,34.091,36.123}, {4.601,5.229,6.262,7.261,8.547,14.339,19.311,22.307,24.996,27.488,28.259,30.578,32.801,35.628,37.697}, {5.142,5.812,6.908,7.962,9.312,15.338,20.465,23.542,26.296,28.845,29.633,32.000,34.267,37.146,39.252}, {5.697,6.408,7.564,8.672,10.085,16.338,21.615,24.769,27.587,30.191,30.995,33.409,35.718,38.648,40.790}, {6.265,7.015,8.231,9.390,10.865,17.338,22.760,25.989,28.869,31.526,32.346,34.805,37.156,40.136,42.312}, {6.844,7.633,8.907,10.117,11.651,18.338,23.900,27.204,30.144,32.852,33.687,36.191,38.582,41.610,43.820}, {7.434,8.260,9.591,10.851,12.443,19.337,25.038,28.412,31.410,34.170,35.020,37.566,39.997,43.072,45.315}, {8.034,8.897,10.283,11.591,13.240,20.337,26.171,29.615,32.671,35.479,36.343,38.932,41.401,44.522,46.797}, {8.643,9.542,10.982,12.338,14.041,21.337,27.301,30.813,33.924,36.781,37.659,40.289,42.796,45.962,48.268}, {9.260,10.196,11.689,13.091,14.848,22.337,28.429,32.007,35.172,38.076,38.968,41.638,44.181,47.391,49.728}, {9.886,10.856,12.401,13.848,15.659,23.337,29.553,33.196,36.415,39.364,40.270,42.980,45.559,48.812,51.179}, {10.520,11.524,13.120,14.611,16.473,24.337,30.675,34.382,37.652,40.646,41.566,44.314,46.928,50.223,52.620}, {11.160,12.198,13.844,15.379,17.292,25.336,31.795,35.563,38.885,41.923,42.856,45.642,48.290,51.627,54.052}, {11.808,12.879,14.573,16.151,18.114,26.336,32.912,36.741,40.113,43.195,44.140,46.963,49.645,53.023,55.476}, {12.461,13.565,15.308,16.928,18.939,27.336,34.027,37.916,41.337,44.461,45.419,48.278,50.993,54.411,56.892}, {13.121,14.256,16.047,17.708,19.768,28.336,35.139,39.087,42.557,45.722,46.693,49.588,52.336,55.792,58.301}, {13.787,14.953,16.791,18.493,20.599,29.336,36.250,40.256,43.773,46.979,47.962,50.892,53.672,57.167,59.703}, {14.458,15.655,17.539,19.281,21.434,30.336,37.359,41.422,44.985,48.232,49.226,52.191,55.003,58.536,61.098}, {15.134,16.362,18.291,20.072,22.271,31.336,38.466,42.585,46.194,49.480,50.487,53.486,56.328,59.899,62.487}, {15.815,17.074,19.047,20.867,23.110,32.336,39.572,43.745,47.400,50.725,51.743,54.776,57.648,61.256,63.870}, {16.501,17.789,19.806,21.664,23.952,33.336,40.676,44.903,48.602,51.966,52.995,56.061,58.964,62.608,65.247}, {17.192,18.509,20.569,22.465,24.797,34.336,41.778,46.059,49.802,53.203,54.244,57.342,60.275,63.955,66.619}, {17.887,19.233,21.336,23.269,25.643,35.336,42.879,47.212,50.998,54.437,55.489,58.619,61.581,65.296,67.985}, {18.586,19.960,22.106,24.075,26.492,36.336,43.978,48.363,52.192,55.668,56.730,59.892,62.883,66.633,69.346}, {19.289,20.691,22.878,24.884,27.343,37.335,45.076,49.513,53.384,56.896,57.969,61.162,64.181,67.966,70.703}, {19.996,21.426,23.654,25.695,28.196,38.335,46.173,50.660,54.572,58.120,59.204,62.428,65.476,69.294,72.055}, {20.707,22.164,24.433,26.509,29.051,39.335,47.269,51.805,55.758,59.342,60.436,63.691,66.766,70.618,73.402}, {21.421,22.906,25.215,27.326,29.907,40.335,48.363,52.949,56.942,60.561,61.665,64.950,68.053,71.938,74.745}, {22.138,23.650,25.999,28.144,30.765,41.335,49.456,54.090,58.124,61.777,62.892,66.206,69.336,73.254,76.084}, {22.859,24.398,26.785,28.965,31.625,42.335,50.548,55.230,59.304,62.990,64.116,67.459,70.616,74.566,77.419}, {23.584,25.148,27.575,29.787,32.487,43.335,51.639,56.369,60.481,64.201,65.337,68.710,71.893,75.874,78.750}, {24.311,25.901,28.366,30.612,33.350,44.335,52.729,57.505,61.656,65.410,66.555,69.957,73.166,77.179,80.077}, {25.041,26.657,29.160,31.439,34.215,45.335,53.818,58.641,62.830,66.617,67.771,71.201,74.437,78.481,81.400}, {25.775,27.416,29.956,32.268,35.081,46.335,54.906,59.774,64.001,67.821,68.985,72.443,75.704,79.780,82.720}, {26.511,28.177,30.755,33.098,35.949,47.335,55.993,60.907,65.171,69.023,70.197,73.683,76.969,81.075,84.037}, {27.249,28.941,31.555,33.930,36.818,48.335,57.079,62.038,66.339,70.222,71.406,74.919,78.231,82.367,85.351}, {27.991,29.707,32.357,34.764,37.689,49.335,58.164,63.167,67.505,71.420,72.613,76.154,79.490,83.657,86.661} }; MMFLOAT q[4]={1,0,0,0}; MMFLOAT eInt[3]={0,0,0}; /* An implementation of the MT19937 Algorithm for the Mersenne Twister * by Evan Sultanik. Based upon the pseudocode in: M. Matsumoto and * T. Nishimura, "Mersenne Twister: A 623-dimensionally * equidistributed uniform pseudorandom number generator," ACM * Transactions on Modeling and Computer Simulation Vol. 8, No. 1, * January pp.3-30 1998. * * http://www.sultanik.com/Mersenne_twister */ struct tagMTRand *g_myrand=NULL; #define UPPER_MASK 0x80000000 #define LOWER_MASK 0x7fffffff #define TEMPERING_MASK_B 0x9d2c5680 #define TEMPERING_MASK_C 0xefc60000 s_PIDchan PIDchannels[MAXPID+1]={0}; inline static void m_seedRand(MTRand* rand, unsigned long seed) { /* set initial seeds to mt[STATE_VECTOR_LENGTH] using the generator * from Line 25 of Table 1 in: Donald Knuth, "The Art of Computer * Programming," Vol. 2 (2nd Ed.) pp.102. */ rand->mt[0] = seed & 0xffffffff; for(rand->index=1; rand->indexindex++) { rand->mt[rand->index] = (6069 * rand->mt[rand->index-1]) & 0xffffffff; } } /** * Creates a new random number generator from a given seed. */ void seedRand(unsigned long seed) { m_seedRand(g_myrand, seed); // return rand; } /** * Generates a pseudo-randomly generated long. */ unsigned long genRandLong(MTRand* rand) { unsigned long y; static unsigned long mag[2] = {0x0, 0x9908b0df}; /* mag[x] = x * 0x9908b0df for x = 0,1 */ if(rand->index >= STATE_VECTOR_LENGTH || rand->index < 0) { /* generate STATE_VECTOR_LENGTH words at a time */ int kk; if(rand->index >= STATE_VECTOR_LENGTH+1 || rand->index < 0) { m_seedRand(rand, 4357); } for(kk=0; kkmt[kk] & UPPER_MASK) | (rand->mt[kk+1] & LOWER_MASK); rand->mt[kk] = rand->mt[kk+STATE_VECTOR_M] ^ (y >> 1) ^ mag[y & 0x1]; } for(; kkmt[kk] & UPPER_MASK) | (rand->mt[kk+1] & LOWER_MASK); rand->mt[kk] = rand->mt[kk+(STATE_VECTOR_M-STATE_VECTOR_LENGTH)] ^ (y >> 1) ^ mag[y & 0x1]; } y = (rand->mt[STATE_VECTOR_LENGTH-1] & UPPER_MASK) | (rand->mt[0] & LOWER_MASK); rand->mt[STATE_VECTOR_LENGTH-1] = rand->mt[STATE_VECTOR_M-1] ^ (y >> 1) ^ mag[y & 0x1]; rand->index = 0; } y = rand->mt[rand->index++]; y ^= (y >> 11); y ^= (y << 7) & TEMPERING_MASK_B; y ^= (y << 15) & TEMPERING_MASK_C; y ^= (y >> 18); return y; } unsigned char b64_chr[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; unsigned int b64_int(unsigned int ch) { // ASCII to base64_int // 65-90 Upper Case >> 0-25 // 97-122 Lower Case >> 26-51 // 48-57 Numbers >> 52-61 // 43 Plus (+) >> 62 // 47 Slash (/) >> 63 // 61 Equal (=) >> 64~ if (ch==43) return 62; if (ch==47) return 63; if (ch==61) return 64; if ((ch>47) && (ch<58)) return ch + 4; if ((ch>64) && (ch<91)) return ch - 'A'; if ((ch>96) && (ch<123)) return (ch - 'a') + 26; return 0; } unsigned int b64e_size(unsigned int in_size) { // size equals 4*floor((1/3)*(in_size+2)); int i, j = 0; for (i=0;i>2 ]; out[k+1] = b64_chr[ ((s[0]&0x03)<<4)+((s[1]&0xF0)>>4) ]; out[k+2] = b64_chr[ ((s[1]&0x0F)<<2)+((s[2]&0xC0)>>6) ]; out[k+3] = b64_chr[ s[2]&0x3F ]; j=0; k+=4; } } if (j) { if (j==1) s[1] = 0; out[k+0] = b64_chr[ (s[0]&255)>>2 ]; out[k+1] = b64_chr[ ((s[0]&0x03)<<4)+((s[1]&0xF0)>>4) ]; if (j==2) out[k+2] = b64_chr[ ((s[1]&0x0F)<<2) ]; else out[k+2] = '='; out[k+3] = '='; k+=4; } out[k] = '\0'; return k; } unsigned int b64_decode(const unsigned char* in, unsigned int in_len, unsigned char* out) { unsigned int i=0, j=0, k=0, s[4]; for (i=0;i>4); if (s[2]!=64) { out[k+1] = ((s[1]&0x0F)<<4)+((s[2]&0x3C)>>2); if ((s[3]!=64)) { out[k+2] = ((s[2]&0x03)<<6)+(s[3]); k+=3; } else { k+=2; } } else { k+=1; } j=0; } } return k; } /** * Generates a pseudo-randomly generated double in the range [0..1]. */ MMFLOAT genRand(MTRand* rand) { return((MMFLOAT)genRandLong(rand) / (unsigned long)0xffffffff); } MMFLOAT determinant(MMFLOAT **matrix,int size); void transpose(MMFLOAT **matrix,MMFLOAT **matrix_cofactor,MMFLOAT **newmatrix, int size); void cofactor(MMFLOAT **matrix,MMFLOAT **newmatrix,int size); static void floatshellsort(MMFLOAT a[], int n) { long h, l, j; MMFLOAT k; for (h = n; h /= 2;) { for (l = h; l < n; l++) { k = a[l]; for (j = l; j >= h && k < a[j - h]; j -= h) { a[j] = a[j - h]; } a[j] = k; } } } static MMFLOAT* alloc1df (int n) { // int i; MMFLOAT* array; if ((array = (MMFLOAT*) GetMemory(n * sizeof(MMFLOAT))) == NULL) { error("Unable to allocate memory for 1D float array...\n"); exit(0); } // for (i = 0; i < n; i++) { // array[i] = 0.0; // } return array; } static MMFLOAT** alloc2df (int m, int n) { int i; MMFLOAT** array; if ((array = (MMFLOAT **) GetMemory(m * sizeof(MMFLOAT*))) == NULL) { error("Unable to allocate memory for 2D float array...\n"); exit(0); } for (i = 0; i < m; i++) { array[i] = alloc1df(n); } return array; } static void dealloc2df (MMFLOAT** array, int m, int n) { int i; for (i = 0; i < m; i++) { FreeMemorySafe((void **)&array[i]); } FreeMemorySafe((void **)&array); } void Q_Mult(MMFLOAT *q1, MMFLOAT *q2, MMFLOAT *n){ MMFLOAT a1=q1[0],a2=q2[0],b1=q1[1],b2=q2[1],c1=q1[2],c2=q2[2],d1=q1[3],d2=q2[3]; n[0]=a1*a2-b1*b2-c1*c2-d1*d2; n[1]=a1*b2+b1*a2+c1*d2-d1*c2; n[2]=a1*c2-b1*d2+c1*a2+d1*b2; n[3]=a1*d2+b1*c2-c1*b2+d1*a2; n[4]=q1[4]*q2[4]; } void Q_Invert(MMFLOAT *q, MMFLOAT *n){ n[0]=q[0]; n[1]=-q[1]; n[2]=-q[2]; n[3]=-q[3]; n[4]=q[4]; } static uint8_t reverse8(uint8_t in) { uint8_t x = in; x = (((x & 0xAA) >> 1) | ((x & 0x55) << 1)); x = (((x & 0xCC) >> 2) | ((x & 0x33) << 2)); x = ((x >> 4) | (x << 4)); return x; } static uint16_t reverse16(uint16_t in) { uint16_t x = in; x = (((x & 0XAAAA) >> 1) | ((x & 0X5555) << 1)); x = (((x & 0xCCCC) >> 2) | ((x & 0X3333) << 2)); x = (((x & 0xF0F0) >> 4) | ((x & 0X0F0F) << 4)); x = (( x >> 8) | (x << 8)); return x; } static uint16_t reverse12(uint16_t in) { return reverse16(in) >> 4; } static uint32_t reverse32(uint32_t in) { uint32_t x = in; x = (((x & 0xAAAAAAAA) >> 1) | ((x & 0x55555555) << 1)); x = (((x & 0xCCCCCCCC) >> 2) | ((x & 0x33333333) << 2)); x = (((x & 0xF0F0F0F0) >> 4) | ((x & 0x0F0F0F0F) << 4)); x = (((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8)); x = (x >> 16) | (x << 16); return x; } static uint64_t reverse64(uint64_t in) { uint64_t x = in; x = (((x & 0xAAAAAAAAAAAAAAAA) >> 1) | ((x & 0x5555555555555555) << 1)); x = (((x & 0xCCCCCCCCCCCCCCCC) >> 2) | ((x & 0x3333333333333333) << 2)); x = (((x & 0xF0F0F0F0F0F0F0F0) >> 4) | ((x & 0x0F0F0F0F0F0F0F0F) << 4)); x = (((x & 0xFF00FF00FF00FF00) >> 8) | ((x & 0x00FF00FF00FF00FF) << 8)); x = (((x & 0xFFFF0000FFFF0000) >> 16) | ((x & 0x0000FFFF0000FFFF) << 16)); x = (x >> 32) | (x << 32); return x; } /////////////////////////////////////////////////////////////////////////////////// /*MIT License Copyright (c) 2021-2024 Rob Tillaart Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/ // CRC POLYNOME = x8 + x5 + x4 + 1 = 1001 1000 = 0x8C uint8_t crc8(uint8_t *array, uint16_t length, const uint8_t polynome, const uint8_t startmask, const uint8_t endmask, const uint8_t reverseIn, const uint8_t reverseOut) { uint8_t crc = startmask; while (length--) { if ((length & 0xFF) == 0) routinechecks(); // RTOS uint8_t data = *array++; if (reverseIn) data = reverse8(data); crc ^= data; for (uint8_t i = 8; i; i--) { if (crc & 0x80) { crc <<= 1; crc ^= polynome; } else { crc <<= 1; } } } crc ^= endmask; if (reverseOut) crc = reverse8(crc); return crc; } // CRC POLYNOME = x12 + x3 + x2 + 1 = 0000 1000 0000 1101 = 0x80D uint16_t crc12(const uint8_t *array, uint16_t length, const uint16_t polynome, const uint16_t startmask, const uint16_t endmask, const uint8_t reverseIn, const uint8_t reverseOut) { uint16_t crc = startmask; while (length--) { if ((length & 0xFF) == 0) routinechecks(); // RTOS uint8_t data = *array++; if (reverseIn) data = reverse8(data); crc ^= ((uint16_t)data) << 4; for (uint8_t i = 8; i; i--) { if (crc & (1 << 11) ) { crc <<= 1; crc ^= polynome; } else { crc <<= 1; } } } if (reverseOut) crc = reverse12(crc); crc ^= endmask; return crc; } // CRC POLYNOME = x15 + 1 = 1000 0000 0000 0001 = 0x8001 uint16_t crc16(const uint8_t *array, uint16_t length, const uint16_t polynome, const uint16_t startmask, const uint16_t endmask, const uint8_t reverseIn, const uint8_t reverseOut) { uint16_t crc = startmask; while (length--) { if ((length & 0xFF) == 0) routinechecks(); // RTOS uint8_t data = *array++; if (reverseIn) data = reverse8(data); crc ^= ((uint16_t)data) << 8; for (uint8_t i = 8; i; i--) { if (crc & (1 << 15)) { crc <<= 1; crc ^= polynome; } else { crc <<= 1; } } } if (reverseOut) crc = reverse16(crc); crc ^= endmask; return crc; } // CRC-CCITT POLYNOME = x13 + X5 + 1 = 0001 0000 0010 0001 = 0x1021 uint16_t crc16_CCITT(uint8_t *array, uint16_t length) { return crc16(array, length, 0x1021, 0xFFFF,0,0,0); } // CRC-32 POLYNOME = x32 + ..... + 1 uint32_t crc32(const uint8_t *array, uint16_t length, const uint32_t polynome, const uint32_t startmask, const uint32_t endmask, const uint8_t reverseIn, const uint8_t reverseOut) { uint32_t crc = startmask; while (length--) { if ((length & 0xFF) == 0) routinechecks(); // RTOS uint8_t data = *array++; if (reverseIn) data = reverse8(data); crc ^= ((uint32_t) data) << 24; for (uint8_t i = 8; i; i--) { if (crc & (1UL << 31)) { crc <<= 1; crc ^= polynome; } else { crc <<= 1; } } } crc ^= endmask; if (reverseOut) crc = reverse32(crc); return crc; } // CRC-CCITT POLYNOME = x64 + ..... + 1 // CRC_ECMA64 = 0x42F0E1EBA9EA3693 uint64_t crc64(const uint8_t *array, uint16_t length, const uint64_t polynome, const uint64_t startmask, const uint64_t endmask, const uint8_t reverseIn, const uint8_t reverseOut) { uint64_t crc = startmask; while (length--) { if ((length & 0xFF) == 0) routinechecks(); // RTOS uint8_t data = *array++; if (reverseIn) data = reverse8(data); crc ^= ((uint64_t) data) << 56; for (uint8_t i = 8; i; i--) { if (crc & (1ULL << 63)) { crc <<= 1; crc ^= polynome; } else { crc <<= 1; } } } crc ^= endmask; if (reverseOut) crc = reverse64(crc); return crc; } #ifdef rp2350 int parseintegerarray(unsigned char *tp, int64_t **a1int, int argno, int dimensions, int *dims, bool ConstantNotAllowed){ #else int parseintegerarray(unsigned char *tp, int64_t **a1int, int argno, int dimensions, short *dims, bool ConstantNotAllowed){ #endif void *ptr1 = NULL; int i,j; ptr1 = findvar(tp, V_FIND | V_EMPTY_OK | V_NOFIND_ERR); if((g_vartbl[g_VarIndex].type & T_CONST) && ConstantNotAllowed) error("Cannot change a constant"); if(dims==NULL)dims=g_vartbl[g_VarIndex].dims; if(g_vartbl[g_VarIndex].type & T_INT) { #ifdef rp2350 memcpy(dims,g_vartbl[g_VarIndex].dims, MAXDIM * sizeof(int)); #else memcpy(dims,g_vartbl[g_VarIndex].dims, MAXDIM * sizeof(short)); #endif *a1int = (int64_t *)ptr1; if((uint32_t)ptr1!=(uint32_t)g_vartbl[g_VarIndex].val.s)error("Syntax"); } else error("Argument % must be an integer array",argno); int card=1; if(dimensions==1 && (dims[0]<=0 || dims[1]>0))error("Argument % must be a 1D integer point array",argno); if(dimensions==2 && (dims[0]<=0 || dims[1]<=0 || dims[2]>0))error("Argument % must be a 2D integer point array",argno); for(i=0;i0))error("Argument % must be a 1D string array",argno); if(dimensions==2 && (dims[0]<=0 || dims[1]<=0 || dims[2]>0))error("Argument % must be a 2D string array",argno); for(i=0;i0))error("Argument % must be a 1D numerical array",argno); if(dimensions==2 && (dims[0]<=0 || dims[1]<=0 || dims[2]>0))error("Argument % must be a 2D numerical array",argno); for(i=0;i0))error("Argument % must be a 1D floating point array",argno); if(dimensions==2 && (dims[0]<=0 || dims[1]<=0 || dims[2]>0))error("Argument % must be a 2D floating point array",argno); for(i=0;iarraylength)error("Array size"); *a1float = (MMFLOAT *)ptr1; if((uint32_t)ptr1!=(uint32_t)g_vartbl[g_VarIndex].val.s)error("Syntax"); } else if(ptr1 && g_vartbl[g_VarIndex].type & T_INT) { if(g_vartbl[g_VarIndex].dims[1] != 0) error("Invalid variable"); if(g_vartbl[g_VarIndex].dims[0] <= 0) { // Not an array error("Argument 1 must be a numerical array"); } arraylength=g_vartbl[g_VarIndex].dims[0] - g_OptionBase + 1; if(*length==0)*length=arraylength; if(*length>arraylength)error("Array size"); *a1int = (int64_t *)ptr1; if((uint32_t)ptr1!=(uint32_t)g_vartbl[g_VarIndex].val.s)error("Syntax"); } else if(ptr1 && g_vartbl[g_VarIndex].type & T_STR && !stringarray) { *a1str=(unsigned char *)ptr1; if(*length==0)*length=**a1str; if(**a1str<*length)error("String size"); } else if(ptr1 && g_vartbl[g_VarIndex].type & T_STR && stringarray) { if(g_vartbl[g_VarIndex].dims[1] != 0) error("Invalid variable"); if(g_vartbl[g_VarIndex].dims[0] <= 0) { // Not an array error("Argument 1 must be a string array"); } arraylength=g_vartbl[g_VarIndex].dims[0] - g_OptionBase + 1; if(*length==0)*length=arraylength; if(*length>arraylength)error("Array size"); *a1str=(unsigned char *)ptr1; if((uint32_t)ptr1!=(uint32_t)g_vartbl[g_VarIndex].val.s)error("Syntax"); *length=g_vartbl[g_VarIndex].size; return arraylength; } else error("Syntax"); return *length; } unsigned char * parseAES(uint8_t *p, int ivadd, uint8_t *keyx, uint8_t *ivx, int64_t **outint, unsigned char **outstr, MMFLOAT **outfloat, int *card2){ int64_t *a1int=NULL, *a2int=NULL, *a3int=NULL, *a4int=NULL; unsigned char *a1str=NULL, *a2str=NULL,*a3str=NULL,*a4str=NULL; MMFLOAT *a1float=NULL, *a2float=NULL, *a3float=NULL, *a4float=NULL; int card1, card3; getargs(&p,7,(unsigned char *)","); if(ivx==NULL){ if(argc!=5)error("Syntax"); } else { if(argc<5)error("Syntax"); } *outstr=NULL; *outint=NULL; int length=0; card1= parseany(argv[0], &a1float, &a1int, &a1str, &length, false); if(card1!=16)error("Key must be 16 elements long"); length=0; *card2= parseany(argv[2], &a2float, &a2int, &a2str, &length, false); if(*card2 % 16)error("input must be multiple of 16 elements long"); // if(card2 >256)error("input must be <= 256 elements long"); unsigned char *inx=(unsigned char *)GetTempMemory(*card2+16); length=0; card3= parseany(argv[4], &a3float, &a3int, &a3str, &length, false); if(card3!=*card2 + ivadd && a3str==NULL)error("Array size mismatch"); if(argc==7){ length=0; card1= parseany(argv[6], &a4float, &a4int, &a4str, &length, false); if(card1!=16)error("Initialisation vector must be 16 elements long"); if(a4int!=NULL){ for(int i=0;i<16;i++){ if(a4int[i]<0 || a4int[i]>255)error("Key number out of bounds 0-255"); ivx[i]=a4int[i]; } } else if (a4float!=NULL){ for(int i=0;i<16;i++){ if(a4float[i]<0 || a4float[i]>255)error("Key number out of bounds 0-255"); ivx[i]=a4float[i]; } } else if(a4str!=NULL){ for(int i=0;i<16;i++){ ivx[i]=a4str[i+1]; } } } if(a1int!=NULL){ for(int i=0;i<16;i++){ if(a1int[i]<0 || a1int[i]>255)error("Key number out of bounds 0-255"); keyx[i]=a1int[i]; } } else if (a1float!=NULL){ for(int i=0;i<16;i++){ if(a1float[i]<0 || a1float[i]>255)error("Key number out of bounds 0-255"); keyx[i]=a1float[i]; } } else if(a1str!=NULL){ for(int i=0;i<16;i++){ keyx[i]=a1str[i+1]; } } if(a2int!=NULL){ for(int i=0;i<*card2;i++){ if(a2int[i]<0 || a2int[i]>255)error("input number out of bounds 0-255"); inx[i]=a2int[i]; } } else if (a2float!=NULL){ for(int i=0;i<*card2;i++){ if(a2float[i]<0 || a2float[i]>255)error("input number out of bounds 0-255"); inx[i]=a2float[i]; } } else if(a2str!=NULL){ for(int i=0;i<*card2;i++){ inx[i]=a2str[i+1]; } } if(a3int!=NULL){ *outint=a3int; } else if (a3float!=NULL){ *outfloat=a3float; } else if(a3str!=NULL){ *outstr=a3str; } return inx; } unsigned char * parseB64(uint8_t *p,int64_t **outint, unsigned char **outstr, MMFLOAT **outfloat, int *card1, int *card2){ int64_t *a1int=NULL, *a3int=NULL; unsigned char *a1str=NULL,*a3str=NULL; MMFLOAT *a1float=NULL, *a3float=NULL; getargs(&p,3,(unsigned char *)","); if(argc!=3)error("Syntax"); *outstr=NULL; *outint=NULL; int length=0; *card1= parseany(argv[0], &a1float, &a1int, &a1str, &length, false); length=0; *card2= parseany(argv[2], &a3float, &a3int, &a3str, &length, false); unsigned char *keyx=(unsigned char *)GetTempMemory(b64e_size(*card1)+1); if(a1int!=NULL){ for(int i=0;i<*card1;i++){ if(a1int[i]<0 || a1int[i]>255)error("Key number out of bounds 0-255"); keyx[i]=a1int[i]; } } else if (a1float!=NULL){ for(int i=0;i<*card1;i++){ if(a1float[i]<0 || a1float[i]>255)error("Key number out of bounds 0-255"); keyx[i]=a1float[i]; } } else if(a1str!=NULL){ for(int i=0;i<*card1;i++){ keyx[i]=a1str[i+1]; } } if(a3int!=NULL){ *outint=a3int; } else if (a3float!=NULL){ *outfloat=a3float; } else if(a3str!=NULL){ *outstr=a3str; } return keyx; } void returnAES(int64_t *outint, MMFLOAT *outflt, uint8_t *outstr, uint8_t *inx, uint8_t *iv, int card){ if(outint!=NULL){ if(iv){ for(int i=0;i<16;i++){ outint[i]=iv[i]; } for(int i=16;i=256)error("Too many elements for string output"); memcpy(&outstr[1],iv,16); memcpy(&outstr[17],inx,card); *outstr=card+16; } else { if(card>=256)error("Too many elements for string output"); memcpy(&outstr[1],inx,card); *outstr=card; } } } MMFLOAT farr2d(MMFLOAT *arr,int d1, int a, int b){ arr+=d1*b+a; return *arr; } int64_t iarr2d(int64_t *arr,int d1, int a, int b){ arr+=d1*b+a; return *arr; } MMFLOAT PIDController_Update(PIDController *pid, MMFLOAT setpoint, MMFLOAT measurement) { /* * Error signal */ MMFLOAT error = setpoint - measurement; /* * Proportional */ MMFLOAT proportional = pid->Kp * error; /* * Integral */ pid->integrator = pid->integrator + 0.5 * pid->Ki * pid->T * (error + pid->prevError); /* Anti-wind-up via integrator clamping */ if (pid->integrator > pid->limMaxInt) { pid->integrator = pid->limMaxInt; } else if (pid->integrator < pid->limMinInt) { pid->integrator = pid->limMinInt; } /* * Derivative (band-limited differentiator) */ pid->differentiator = -(2.0 * pid->Kd * (measurement - pid->prevMeasurement) /* Note: derivative on measurement, therefore minus sign in front of equation! */ + (2.0 * pid->tau - pid->T) * pid->differentiator) / (2.0 * pid->tau + pid->T); /* * Compute output and apply limits */ pid->out = proportional + pid->integrator + pid->differentiator; if (pid->out > pid->limMax) { pid->out = pid->limMax; } else if (pid->out < pid->limMin) { pid->out = pid->limMin; } /* Store error and measurement for later use */ pid->prevError = error; pid->prevMeasurement = measurement; /* Return controller output */ return pid->out; } /* @endcond */ uint8_t getrnd(void){ #ifdef rp2350 return get_rand_32() & 0xFF; #else return rand() & 0xFF; #endif } void cmd_math(void){ unsigned char *tp; int t = T_NBR; MMFLOAT f; long long int i64; unsigned char *s; #ifdef rp2350 int dims[MAXDIM]={0}; #else short dims[MAXDIM]={0}; #endif skipspace(cmdline); if(toupper(*cmdline)=='S'){ tp = checkstring(cmdline, (unsigned char *)"SET"); if(tp) { array_set(tp); return; } tp = checkstring(cmdline, (unsigned char *)"SCALE"); if(tp) { int i,card1=1, card2=1; MMFLOAT *a1float=NULL,*a2float=NULL, scale; int64_t *a1int=NULL, *a2int=NULL; getargs(&tp, 5,(unsigned char *)","); if(!(argc == 5)) error("Argument count"); card1=parsenumberarray(argv[0],&a1float,&a1int,1,0, dims, false); evaluate(argv[2], &f, &i64, &s, &t, false); if(t & T_STR) error("Syntax"); scale=getnumber(argv[2]); card2=parsenumberarray(argv[4],&a2float,&a2int,3,0, dims, true); if(card1 != card2)error("Size mismatch"); if(scale!=1.0){ if(a2float!=NULL && a1float!=NULL){ for(i=0; i< card1;i++)*a2float++ = ((t & T_INT) ? (MMFLOAT)i64 : f) * (*a1float++); } else if(a2float!=NULL && a1float==NULL){ for(i=0; i< card1;i++)(*a2float++) = ((t & T_INT) ? (MMFLOAT)i64 : f) * ((MMFLOAT)*a1int++); } else if(a2float==NULL && a1float!=NULL){ for(i=0; i< card1;i++)(*a2int++) = FloatToInt64(((t & T_INT) ? i64 : FloatToInt64(f)) * (*a1float++)); } else { for(i=0; i< card1;i++)(*a2int++) = ((t & T_INT) ? i64 : FloatToInt64(f)) * (*a1int++); } } else { if(a2float!=NULL && a1float!=NULL){ for(i=0; i< card1;i++)*a2float++ = *a1float++; } else if(a2float!=NULL && a1float==NULL){ for(i=0; i< card1;i++)(*a2float++) = ((MMFLOAT)*a1int++); } else if(a2float==NULL && a1float!=NULL){ for(i=0; i< card1;i++)(*a2int++) = FloatToInt64(*a1float++); } else { for(i=0; i< card1;i++)*a2int++ = *a1int++; } } return; } tp = checkstring(cmdline, (unsigned char *)"SHIFT"); if(tp) { int i, card1=1, card2=1; int64_t *a1int=NULL, *a2int=NULL; getargs(&tp, 7,(unsigned char *)","); if(!(argc == 5 || argc==7)) error("Argument count"); card1=parseintegerarray(argv[0],&a1int,1,0, dims, false); evaluate(argv[2], &f, &i64, &s, &t, false); int shift=getint(argv[2], -63,63); card2=parseintegerarray(argv[4],&a2int,3,0, dims, true); if(card1 != card2)error("Size mismatch"); if(shift>0)for(i=0; i< card1;i++)*a2int++ = (((uint64_t)*a1int++)<>(-shift)); } else { for(i=0; i< card1;i++)*a2int++ = ((*a1int++)>>(-shift)); } } return; } tp = checkstring(cmdline, (unsigned char *)"SLICE"); if(tp) { array_slice(tp); return; } tp = checkstring(cmdline, (unsigned char *)"SENSORFUSION"); if(tp) { cmd_SensorFusion((char *)tp); return; } } else if(toupper(*cmdline)=='C') { unsigned char *tp1=NULL; tp = checkstring(cmdline, (unsigned char *)"C_ADD"); if(tp) { MMFLOAT *a1float=NULL,*a2float=NULL,*a3float=NULL; int64_t *a1int=NULL,*a2int=NULL,*a3int=NULL; int card=parsearrays(tp, &a1float, &a2float, &a3float, &a1int, &a2int, &a3int); if(a1float){ while(card--){ *a3float++ = *a1float++ + *a2float++; } } else { while(card--){ *a3int++ = *a1int++ + *a2int++; } } return; } tp = checkstring(cmdline, (unsigned char *)"C_MUL"); tp1 = checkstring(cmdline, (unsigned char *)"C_MULT"); if(tp || tp1) { if(tp1)tp=tp1; MMFLOAT *a1float=NULL,*a2float=NULL,*a3float=NULL; int64_t *a1int=NULL,*a2int=NULL,*a3int=NULL; int card=parsearrays(tp, &a1float, &a2float, &a3float, &a1int, &a2int, &a3int); if(a1float){ while(card--){ *a3float++ = *a1float++ * *a2float++; } } else { while(card--){ *a3int++ = *a1int++ * *a2int++; } } return; } tp = checkstring(cmdline, (unsigned char *)"C_AND"); if(tp) { MMFLOAT *a1float=NULL,*a2float=NULL,*a3float=NULL; int64_t *a1int=NULL,*a2int=NULL,*a3int=NULL; int card=parsearrays(tp, &a1float, &a2float, &a3float, &a1int, &a2int, &a3int); if(a1float){ while(card--){ *a3float++ = (MMFLOAT)((int64_t)*a1float++ & (int64_t)*a2float++); } } else { while(card--){ *a3int++ = *a1int++ & *a2int++; } } return; } tp = checkstring(cmdline, (unsigned char *)"C_XOR"); if(tp) { MMFLOAT *a1float=NULL,*a2float=NULL,*a3float=NULL; int64_t *a1int=NULL,*a2int=NULL,*a3int=NULL; int card=parsearrays(tp, &a1float, &a2float, &a3float, &a1int, &a2int, &a3int); if(a1float){ while(card--){ *a3float++ = (MMFLOAT)((int64_t)*a1float++ ^ (int64_t)*a2float++); } } else { while(card--){ *a3int++ = *a1int++ & *a2int++; } } return; } tp = checkstring(cmdline, (unsigned char *)"C_OR"); if(tp) { MMFLOAT *a1float=NULL,*a2float=NULL,*a3float=NULL; int64_t *a1int=NULL,*a2int=NULL,*a3int=NULL; int card=parsearrays(tp, &a1float, &a2float, &a3float, &a1int, &a2int, &a3int); if(a1float){ while(card--){ *a3float++ = (MMFLOAT)((int64_t)*a1float++ | (int64_t)*a2float++); } } else { while(card--){ *a3int++ = *a1int++ & *a2int++; } } return; } tp = checkstring(cmdline, (unsigned char *)"C_SUB"); if(tp) { MMFLOAT *a1float=NULL,*a2float=NULL,*a3float=NULL; int64_t *a1int=NULL,*a2int=NULL,*a3int=NULL; int card=parsearrays(tp, &a1float, &a2float, &a3float, &a1int, &a2int, &a3int); if(a1float){ while(card--){ *a3float++ = *a1float++ - *a2float++; } } else { while(card--){ *a3int++ = *a1int++ - *a2int++; } } return; } tp = checkstring(cmdline, (unsigned char *)"C_DIV"); if(tp) { MMFLOAT *a1float=NULL,*a2float=NULL,*a3float=NULL; int64_t *a1int=NULL,*a2int=NULL,*a3int=NULL; int card=parsearrays(tp, &a1float, &a2float, &a3float, &a1int, &a2int, &a3int); if(a1float){ while(card--){ *a3float++ = *a1float++ / *a2float++; } } else { while(card--){ *a3int++ = *a1int++ / *a2int++; } } return; } } else if(toupper(*cmdline)=='V') { tp = checkstring(cmdline, (unsigned char *)"V_MULT"); if(tp) { int i,j, numcols=0, numrows=0; MMFLOAT *a1float=NULL,*a2float=NULL,*a2sfloat=NULL,*a3float=NULL; getargs(&tp, 5,(unsigned char *)","); if(!(argc == 5)) error("Argument count"); parsefloatrarray(argv[0],&a1float,1,2,dims,false); numcols=dims[0] - g_OptionBase; numrows=dims[1] - g_OptionBase; parsefloatrarray(argv[2],&a2float,1,1,dims,false); if((dims[0] - g_OptionBase) != numcols)error("Array size mismatch"); parsefloatrarray(argv[4],&a3float,1,1,dims,true); if((dims[0] - g_OptionBase) != numrows)error("Array size mismatch"); if(a3float==a1float || a3float==a2float)error("Destination array same as source"); a2sfloat=a2float; numcols++; numrows++; for(i=0;iT * 1000); PIDchannels[channel].active=true; InterruptUsed=true; } else if((pi=checkstring(tp, (unsigned char *)"STOP"))){ int channel = getint(pi,1,MAXPID); if(PIDchannels[channel].interrupt==NULL)error("Channel not initialised"); PIDchannels[channel].active=false; memset(&PIDchannels[channel],0,sizeof(s_PIDchan)); } else if((pi=checkstring(tp, (unsigned char *)"INIT"))){ getargs(&pi,5,(unsigned char *)","); if(argc!=5)error("Syntax"); MMFLOAT *q1=NULL; int channel = getint(argv[0],1,MAXPID); int card=parsefloatrarray(argv[2],&q1,2,1, NULL, true); PIDchannels[channel].PIDparams=(PIDController *)q1; if(card!=14)error("Argument 2 must be a 14 element floating point array"); if(PIDchannels[channel].PIDparams->T < 0.001)error("Invalid update rate"); PIDchannels[channel].interrupt=GetIntAddress(argv[4]); } else error("Syntax"); return; } tp = checkstring(cmdline, (unsigned char *)"ADD"); if(tp) { array_add(tp); return; } tp = checkstring(cmdline, (unsigned char *)"POWER"); if(tp) { int i,card1=1, card2=1; MMFLOAT *a1float=NULL,*a2float=NULL, scale; int64_t *a1int=NULL, *a2int=NULL; getargs(&tp, 5,(unsigned char *)","); if(!(argc == 5)) error("Argument count"); card1=parsenumberarray(argv[0], &a1float, &a1int, 1, 0,dims, false); evaluate(argv[2], &f, &i64, &s, &t, false); if(t & T_STR) error("Syntax"); scale=getnumber(argv[2]); card2=parsenumberarray(argv[4], &a2float, &a2int, 3, 0,dims, true); if(card1 != card2)error("Array size mismatch"); if(scale!=1.0){ if(a2float!=NULL && a1float!=NULL){ for(i=0; i< card1;i++)*a2float++ = pow(*a1float++,(t & T_INT) ? (MMFLOAT)i64 : f); } else if(a2float!=NULL && a1float==NULL){ for(i=0; i< card1;i++)(*a2float++) = pow((MMFLOAT)*a1int++,((t & T_INT) ? (MMFLOAT)i64 : f)); } else if(a2float==NULL && a1float!=NULL){ for(i=0; i< card1;i++)(*a2int++) = FloatToInt64(pow(*a1float++,((t & T_INT) ? i64 : FloatToInt64(f)))); } else { for(i=0; i< card1;i++)(*a2int++) = FloatToInt64(pow(*a1int++,(t & T_INT) ? i64 : FloatToInt64(f))); } } else { if(a2float!=NULL && a1float!=NULL){ for(i=0; i< card1;i++)*a2float++ = *a1float++; } else if(a2float!=NULL && a1float==NULL){ for(i=0; i< card1;i++)(*a2float++) = ((MMFLOAT)*a1int++); } else if(a2float==NULL && a1float!=NULL){ for(i=0; i< card1;i++)(*a2int++) = FloatToInt64(*a1float++); } else { for(i=0; i< card1;i++)*a2int++ = *a1int++; } } return; } tp = checkstring(cmdline, (unsigned char *)"WINDOW"); if(tp) { int i,card1=1, card2=1; MMFLOAT *a1float=NULL,*a2float=NULL, outmin,outmax, inmin=1.5e+308 , inmax=-1.5e308; int64_t *a1int=NULL, *a2int=NULL; getargs(&tp, 11,(unsigned char *)","); if(!(argc == 7 || argc==11)) error("Argument count"); card1=parsenumberarray(argv[0], &a1float, &a1int, 1, 0,dims, false); outmin=getnumber(argv[2]); outmax=getnumber(argv[4]); card2=parsenumberarray(argv[6], &a2float, &a2int, 4, 0,dims, true); if(card1 != card2)error("Size mismatch"); for(i=0; i< card1;i++){ if(a1float!=NULL){ //find min and max if in is a float if(a1float[i]inmax)inmax=a1float[i]; } else { if(a1int[i]inmax)inmax=(MMFLOAT)a1int[i]; } } if(argc==11){ void *ptr1 = findvar(argv[8], V_FIND); if(!(g_vartbl[g_VarIndex].type & (T_NBR | T_INT))) error("Invalid variable"); if(g_vartbl[g_VarIndex].type==T_INT)*(long long int *)ptr1=(long long int)inmin; else *(MMFLOAT *)ptr1=inmin; void *ptr2 = findvar(argv[10], V_FIND); if(!(g_vartbl[g_VarIndex].type & (T_NBR | T_INT))) error("Invalid variable"); if(g_vartbl[g_VarIndex].type==T_INT)*(long long int *)ptr2=(long long int)inmax; else *(MMFLOAT *)ptr2=inmax; } if(a2float!=NULL && a1float!=NULL){ //in and out are floats for(i=0; i< card1;i++)a2float[i] = ((a1float[i]-inmin)/(inmax-inmin))*(outmax-outmin)+outmin; } else if(a2float==NULL && a1float!=NULL){ //in is a float and out is an integer for(i=0; i< card1;i++)a2int[i] =(long long int)(((a1float[i]-inmin)/(inmax-inmin))*(outmax-outmin)+outmin); } else if(a2float!=NULL && a1float==NULL){ //in is an integer and out is a float for(i=0; i< card1;i++)a2float[i] =((((MMFLOAT)a1int[i]-inmin)/(inmax-inmin))*(outmax-outmin)+outmin); } else { // in and out are integers for(i=0; i< card1;i++)a2int[i] =(long long int)((((MMFLOAT)a1int[i]-inmin)/(inmax-inmin))*(outmax-outmin)+outmin); } return; } tp = checkstring(cmdline, (unsigned char *)"RANDOMIZE"); if(tp) { int i; getargs(&tp,1,(unsigned char *)","); if(argc==1)i = getinteger(argv[0]); else i=time_us_32(); if(i < 0) error("Number out of bounds"); if(g_myrand==NULL)g_myrand=(struct tagMTRand *)GetMemory(sizeof(struct tagMTRand)); seedRand(i); return; } tp = checkstring(cmdline, (unsigned char *)"INTERPOLATE"); if(tp) { int i,card1, card2, card3; MMFLOAT *a1float=NULL,*a2float=NULL, *a3float=NULL, scale, tmp1, tmp2, tmp3; int64_t *a1int=NULL, *a2int=NULL, *a3int=NULL; getargs(&tp, 7,(unsigned char *)","); if(!(argc == 7)) error("Argument count"); card1=parsenumberarray(argv[0], &a1float, &a1int, 1, 0, dims, false); evaluate(argv[4], &f, &i64, &s, &t, false); if(t & T_STR) error("Syntax"); scale=getnumber(argv[4]); card2=parsenumberarray(argv[2], &a2float, &a2int, 3, 0, dims, false); card3=parsenumberarray(argv[6], &a3float, &a3int, 4, 0, dims, true); if((card1 != card2) || (card1!=card3))error("Size mismatch"); if(a3int!=NULL){ if((a1int==a2int) || (a1int==a3int) || (a2int==a3int))error("Arrays must be different"); for(i=0; i< card1;i++){ if(a1int!=NULL)tmp1=(MMFLOAT)*a1int++; else tmp1=*a1float++; if(a2int!=NULL)tmp2=(MMFLOAT)*a2int++; else tmp2=*a2float++; tmp3=(tmp2-tmp1)*scale + tmp1; *a3int++=FloatToInt64(tmp3); } } else { if((a1float==a2float) || (a1float==a3float) || (a2float==a3float))error("Arrays must be different"); for(i=0; i< card1;i++){ if(a1int!=NULL)tmp1=(MMFLOAT)*a1int++; else tmp1=*a1float++; if(a2int!=NULL)tmp2=(MMFLOAT)*a2int++; else tmp2=*a2float++; tmp3=(tmp2-tmp1)*scale + tmp1; *a3float++=tmp3; } } return; } tp = checkstring(cmdline, (unsigned char *)"INSERT"); if(tp) { array_insert(tp); return; } tp = checkstring(cmdline, (unsigned char *)"FFT"); if(tp) { cmd_FFT(tp); return; } } error("Syntax"); } /* * @cond * The following section will be excluded from the documentation. */ fcplx getComplex(unsigned char *in){ int64_t i=getinteger(in); fcplx x; memcpy(&x, &i, 8); return x; } void retComplex(fcplx in){ iret=0; memcpy(&iret, &in, 8); targ=T_INT; } /* @endcond */ void fun_math(void){ unsigned char *tp, *tp1; #ifdef rp2350 int dims[MAXDIM]={0}; #else short dims[MAXDIM]={0}; #endif skipspace(ep); if(toupper(*ep)=='P'){ tp = checkstring(ep, (unsigned char *)"PID"); if(tp){ getargs(&tp, 5,(unsigned char *)","); if(argc != 5)error("Syntax"); int channel=getint(argv[0],1,MAXPID); MMFLOAT setpoint=getnumber(argv[2]); MMFLOAT measurement=getnumber(argv[4]); if(PIDchannels[channel].interrupt==NULL)error("Channel not configured"); if(!PIDchannels[channel].active)error("Channel not active"); fret=PIDController_Update(PIDchannels[channel].PIDparams, setpoint, measurement); targ=T_NBR; return; } } if(toupper(*ep)=='A'){ tp = checkstring(ep, (unsigned char *)"ATAN3"); if(tp) { MMFLOAT y,x,z; getargs(&tp, 3,(unsigned char *)","); if(argc != 3)error("Syntax"); y=getnumber(argv[0]); x=getnumber(argv[2]); z=atan2(y,x); if (z < 0.0) z = z + M_TWOPI; fret=z; fret *=optionangle; targ = T_NBR; return; } } else if(toupper(*ep)=='C') { if(ep[1]=='_'){ if((tp=checkstring(&ep[2],(unsigned char *)"REAL"))){ fret=(MMFLOAT)crealf(getComplex(tp)); targ=T_NBR; } else if((tp=checkstring(&ep[2],(unsigned char *)"IMAG"))){ fret=(MMFLOAT)cimagf(getComplex(tp)); targ=T_NBR; } else if((tp=checkstring(&ep[2],(unsigned char *)"MOD"))){ MMFLOAT a=(MMFLOAT)crealf(getComplex(tp)); MMFLOAT b=(MMFLOAT)cimagf(getComplex(tp)); a*=a; b*=b; b+=a; fret=sqrt(b); targ=T_NBR; } else if((tp=checkstring(&ep[2],(unsigned char *)"PHASE"))){ MMFLOAT a=(MMFLOAT)crealf(getComplex(tp)); MMFLOAT b=(MMFLOAT)cimagf(getComplex(tp)); fret=atan2(b,a); if(useoptionangle)fret*=optionangle; targ=T_NBR; } else if((tp=checkstring(&ep[2],(unsigned char *)"CARG"))){ fret=(MMFLOAT)cargf(getComplex(tp)); targ=T_NBR; } else if((tp=checkstring(&ep[2],(unsigned char *)"ADD"))){ getargs(&tp,3,(unsigned char *)","); fcplx x=getComplex(argv[0])+getComplex(argv[2]); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"MUL"))){ getargs(&tp,3,(unsigned char *)","); fcplx x=getComplex(argv[0])*getComplex(argv[2]); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"SUB"))){ getargs(&tp,3,(unsigned char *)","); fcplx x=getComplex(argv[0])-getComplex(argv[2]); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"DIV"))){ getargs(&tp,3,(unsigned char *)","); fcplx x=getComplex(argv[0])/getComplex(argv[2]); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"POW"))){ getargs(&tp,3,(unsigned char *)","); fcplx x=cpowf(getComplex(argv[0]),getComplex(argv[2])); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"CONJ"))){ fcplx x=conjf(getComplex(tp)); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"ACOS"))){ fcplx x=cacosf(getComplex(tp)); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"ASIN"))){ fcplx x=casinf(getComplex(tp)); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"ATAN"))){ fcplx x=catanf(getComplex(tp)); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"SIN"))){ fcplx x=csinf(getComplex(tp)); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"COS"))){ fcplx x=ccosf(getComplex(tp)); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"TAN"))){ fcplx x=ctanf(getComplex(tp)); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"SINH"))){ fcplx x=csinhf(getComplex(tp)); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"COSH"))){ fcplx x=ccoshf(getComplex(tp)); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"TANH"))){ fcplx x=ctanhf(getComplex(tp)); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"ASINH"))){ fcplx x=casinhf(getComplex(tp)); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"ACOSH"))){ fcplx x=cacoshf(getComplex(tp)); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"ATANH"))){ fcplx x=catanhf(getComplex(tp)); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"EXP"))){ fcplx x=cexpf(getComplex(tp)); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"LOG"))){ fcplx x=clogf(getComplex(tp)); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"ABS"))){ fcplx x=cabsf(getComplex(tp)); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"SQRT"))){ fcplx x=csqrtf(getComplex(tp)); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"PROJ"))){ fcplx x=cprojf(getComplex(tp)); retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"CPLX"))){ getargs(&tp,3,(unsigned char *)","); fcplx x=(float)(getnumber(argv[0]))+(float)(getnumber(argv[2]))*I; retComplex(x); } else if((tp=checkstring(&ep[2],(unsigned char *)"POLAR"))){ getargs(&tp,3,(unsigned char *)","); MMFLOAT r=getnumber(argv[0]); MMFLOAT theta=getnumber(argv[2])/optionangle; MMFLOAT stheta=sin(theta)*r; MMFLOAT ctheta=cos(theta)*r; fcplx x=(float)(ctheta)+(float)(stheta)*I; retComplex(x); } else error("Syntax"); return; } tp = checkstring(ep, (unsigned char *)"CRC8"); if(tp) { int i; MMFLOAT *a1float=NULL; int64_t *a1int=NULL; getargs(&tp,13,(unsigned char *)","); if(argc<1)error("Syntax"); uint8_t polynome=CRC8_DEFAULT_POLYNOME; uint8_t startmask=0; uint8_t endmask=0; uint8_t reverseIn=false; uint8_t reverseOut=false; unsigned char *a1str=NULL; int length=0; if(argc>1 && *argv[2])length=getint(argv[2],1,65535); length=parseany(argv[0], &a1float, &a1int, &a1str, &length, false); uint8_t *array=GetTempMemory(length); if(argc>3 && *argv[4])polynome=getint(argv[4],0,255); if(argc>5 && *argv[6])startmask=getint(argv[6],0,255); if(argc>7 && *argv[8])endmask=getint(argv[8],0,255); if(argc>9 && *argv[10])reverseIn=getint(argv[10],0,1); if(argc==13 && *argv[12])reverseOut=getint(argv[10],0,1); for(i=0;i255)error("Variable > 255"); else array[i]=(uint8_t)a1float[i]; } else if(a1int){ if(a1int[i]>255)error("Variable > 255"); else array[i]=(uint8_t)a1int[i]; } else memcpy(array,&a1str[1],length); } iret=crc8(array, length, polynome, startmask, endmask, reverseIn, reverseOut); targ=T_INT; return; } tp = checkstring(ep, (unsigned char *)"CRC12"); if(tp) { int i; MMFLOAT *a1float=NULL; int64_t *a1int=NULL; getargs(&tp,13,(unsigned char *)","); if(argc<1)error("Syntax"); uint16_t polynome=CRC12_DEFAULT_POLYNOME; uint16_t startmask=0; uint16_t endmask=0; uint8_t reverseIn=false; uint8_t reverseOut=false; unsigned char *a1str=NULL; int length=0; if(argc>1 && *argv[2])length=getint(argv[2],1,65535); length=parseany(argv[0], &a1float, &a1int, &a1str, &length, false); uint8_t *array=GetTempMemory(length); if(argc>3 && *argv[4])polynome=getint(argv[4],0,4095); if(argc>5 && *argv[6])startmask=getint(argv[6],0,4095); if(argc>7 && *argv[8])endmask=getint(argv[8],0,4095); if(argc>9 && *argv[10])reverseIn=getint(argv[10],0,1); if(argc==13 && *argv[12])reverseOut=getint(argv[10],0,1); for(i=0;i255)error("Variable > 255"); else array[i]=(uint8_t)a1float[i]; } else if(a1int){ if(a1int[i]>255)error("Variable > 255"); else array[i]=(uint8_t)a1int[i]; } else memcpy(array,&a1str[1],length); } iret=crc12(array, length, polynome, startmask, endmask, reverseIn, reverseOut); targ=T_INT; return; } tp = checkstring(ep, (unsigned char *)"CRC16"); if(tp) { int i; MMFLOAT *a1float=NULL; int64_t *a1int=NULL; getargs(&tp,13,(unsigned char *)","); if(argc<1)error("Syntax"); uint16_t polynome=CRC16_DEFAULT_POLYNOME; uint16_t startmask=0; uint16_t endmask=0; uint8_t reverseIn=false; uint8_t reverseOut=false; unsigned char *a1str=NULL; int length=0; if(argc>1 && *argv[2])length=getint(argv[2],1,65535); length=parseany(argv[0], &a1float, &a1int, &a1str, &length, false); uint8_t *array=GetTempMemory(length); if(argc>3 && *argv[4])polynome=getint(argv[4],0,65535); if(argc>5 && *argv[6])startmask=getint(argv[6],0,65535); if(argc>7 && *argv[8])endmask=getint(argv[8],0,65535); if(argc>9 && *argv[10])reverseIn=getint(argv[10],0,1); if(argc==13 && *argv[12])reverseOut=getint(argv[10],0,1); for(i=0;i255)error("Variable > 255"); else array[i]=(uint8_t)a1float[i]; } else if(a1int){ if(a1int[i]>255)error("Variable > 255"); else array[i]=(uint8_t)a1int[i]; } else memcpy(array,&a1str[1],length); } iret=crc16(array, length, polynome, startmask, endmask, reverseIn, reverseOut); targ=T_INT; return; } tp = checkstring(ep, (unsigned char *)"CRC32"); if(tp) { int i; MMFLOAT *a1float=NULL; int64_t *a1int=NULL; getargs(&tp,13,(unsigned char *)","); if(argc<1)error("Syntax"); uint32_t polynome=CRC32_DEFAULT_POLYNOME; uint32_t startmask=0; uint32_t endmask=0; uint8_t reverseIn=false; uint8_t reverseOut=false; unsigned char *a1str=NULL; int length=0; if(argc>1 && *argv[2])length=getint(argv[2],1,65535); length=parseany(argv[0], &a1float, &a1int, &a1str, &length, false); uint8_t *array=GetTempMemory(length); if(argc>3 && *argv[4])polynome=getint(argv[4],0,0xFFFFFFFF); if(argc>5 && *argv[6])startmask=getint(argv[6],0,0xFFFFFFFF); if(argc>7 && *argv[8])endmask=getint(argv[8],0,0xFFFFFFFF); if(argc>9 && *argv[10])reverseIn=getint(argv[10],0,1); if(argc==13 && *argv[12])reverseOut=getint(argv[10],0,1); for(i=0;i255)error("Variable > 255"); else array[i]=(uint8_t)a1float[i]; } else if(a1int){ if(a1int[i]>255)error("Variable > 255"); else array[i]=(uint8_t)a1int[i]; } else memcpy(array,&a1str[1],length); } iret=crc32(array, length, polynome, startmask, endmask, reverseIn, reverseOut); targ=T_INT; return; } tp = checkstring(ep, (unsigned char *)"COSH"); if(tp) { getargs(&tp, 1,(unsigned char *)","); if(!(argc == 1)) error("Argument count"); fret=cosh(getnumber(argv[0])); targ=T_NBR; return; } tp = checkstring(ep, (unsigned char *)"CROSSING"); if(tp){ MMFLOAT *a1float=NULL; int64_t *a1int=NULL; int arraylength=0; MMFLOAT crossing=0.0; int direction=1; int found=-1; getargs(&tp,5,(unsigned char *)","); if(argc<1)error("Syntax"); if(argc>=3 && *argv[2])crossing = getnumber(argv[2]); if(argc==5) direction=getint(argv[4],-1,1); if(direction==0)error ("Valid are -1 and 1"); arraylength=parsenumberarray(argv[0],&a1float,&a1int,1,1,dims, false); for(int i=0;icrossing && (a1float[i+1]>=a1float[i] && a1float[i+1]<=a1float[i+2]) && direction==1){ found=i+1; break; } if(a1float[i]>crossing && a1float[i+2]=a1float[i+2]) && direction==-1){ found=i+1; break; } } else { if(a1int[i]crossing && (a1int[i+1]>=a1int[i] && a1int[i+1]<=a1int[i+2]) && direction==1){ found=i+1; break; } if(a1int[i]>crossing && a1int[i+2]=a1int[i+2]) && direction==-1){ found=i+1; break; } } } if(found==-1){ //try a slower moving slope for(int i=0;i=crossing && (a1float[i+2]>=a1float[i+1] && a1float[i+2]<=a1float[i+3]) && direction==1){ if(a1float[i]a1float[i+2]){ found=i+2; break; } } if(a1float[i+1]>=crossing && a1float[i+3]<=crossing && (a1float[i+2]<=a1float[i+1] && a1float[i+2]>=a1float[i+3]) && direction==-1){ if(a1float[i]>a1float[i+2] && a1float[i+4]=crossing && (a1int[i+2]>=a1int[i+1] && a1int[i+2]<=a1int[i+3]) && direction==1){ if(a1int[i]a1int[i+2]){ found=i+2; break; } } if(a1int[i+1]>=crossing && a1int[i+3]<=crossing && (a1int[i+2]<=a1int[i+1] && a1int[i+2]>=a1int[i+3]) && direction==-1){ if(a1int[i]>a1int[i+2] && a1int[i+4]prob){ i=7; while(i<15 && chi>=chitable[df][i])i++; chi_prob=chitable[0][i-1]; } else { i=7; while(i>=0 && chi<=chitable[df][i])i--; chi_prob=chitable[0][i+1]; } dealloc2df(observed,numcols,numrows); dealloc2df(expected,numcols,numrows); FreeMemorySafe((void **)&rows); FreeMemorySafe((void **)&cols); targ=T_NBR; fret=(chi_p ? chi_prob*100 : chi); return; } } } else if(toupper(*ep)=='D') { tp = checkstring(ep, (unsigned char *)"DOTPRODUCT"); if(tp) { int i; int card1,card2; MMFLOAT *a1float=NULL, *a2float=NULL; // need two arrays with same cardinality getargs(&tp, 3,(unsigned char *)","); if(!(argc == 3)) error("Argument count"); card1=parsefloatrarray(argv[0],&a1float,1,1,dims, false); card2=parsefloatrarray(argv[2],&a2float,2,1,dims, false); if(card1!=card2)error("Array size mismatch"); fret=0; for(i=0;i 0) { // Not an array error("Argument 1 must be a 1D numerical array"); } temp = findvar(argv[2], V_FIND); if(!(g_vartbl[g_VarIndex].type & T_INT)) error("Invalid variable"); } if(a1float!=NULL){ for(i=0; i< card1;i++){ if((*a1float)>max){ max=(*a1float); if(temp!=NULL){ *temp=i+g_OptionBase; } } a1float++; } } else { for(i=0; i< card1;i++){ if(((MMFLOAT)(*a1int))>max){ max=(MMFLOAT)(*a1int); if(temp!=NULL){ *temp=i+g_OptionBase; } } a1int++; } } targ=T_NBR; fret=max; return; } tp = checkstring(ep, (unsigned char *)"MIN"); if(tp) { int i,card1=1; MMFLOAT *a1float=NULL, min=3.0e+38; int64_t *a1int=NULL; long long int *temp=NULL; getargs(&tp, 3,(unsigned char *)","); // if(!(argc == 1)) error("Argument count"); card1=parsenumberarray(argv[0],&a1float,&a1int,1,0,dims, false); if(argc==3){ if(dims[1] > 0) { // Not an array error("Argument 1 must be a 1D numerical array"); } temp = findvar(argv[2], V_FIND); if(!(g_vartbl[g_VarIndex].type & T_INT)) error("Invalid variable"); } if(a1float!=NULL){ for(i=0; i< card1;i++){ if((*a1float) 255) error("Output exceeds string size"); unsigned char *out =(unsigned char *)GetTempMemory(b64e_size(card+1)); int size = b64_encode(inx, card, out); returnAES(outint, outflt, outstr, out, NULL, size); iret=size; targ=T_INT; return; } else if((p=checkstring(tp, (unsigned char *)"DECODE"))){ unsigned char *inx=parseB64(p, &outint, &outstr, &outflt, &card, &card2); if(!outstr && card2 < b64d_size(card)) error("Output array too small"); if(outstr && b64d_size(card) > 255) error("Output exceeds string size"); unsigned char *out =(unsigned char *)GetTempMemory(b64e_size(card+1)); int size = b64_decode(inx,card,out); returnAES(outint, outflt, outstr, out, NULL, size); iret=size; targ=T_INT; return; } else error("Syntax"); } } error("Syntax"); } static size_t reverse_bits(size_t val, int width) { size_t result = 0; for (int i = 0; i < width; i++, val >>= 1) result = (result << 1) | (val & 1U); return result; } /* * @cond * The following section will be excluded from the documentation. */ bool Fft_transformRadix2(double complex vec[], size_t n, bool inverse) { // Length variables int levels = 0; // Compute levels = floor(log2(n)) for (size_t temp = n; temp > 1U; temp >>= 1) levels++; if ((size_t)1U << levels != n) return false; // n is not a power of 2 // Trigonometric tables if (SIZE_MAX / sizeof(double complex) < n / 2) return false; double complex *exptable = GetMemory((n / 2) * sizeof(double complex)); if (exptable == NULL) return false; for (size_t i = 0; i < n / 2; i++) exptable[i] = cexp((inverse ? 2 : -2) * M_PI * i / n * I); // Bit-reversed addressing permutation for (size_t i = 0; i < n; i++) { size_t j = reverse_bits(i, levels); if (j > i) { double complex temp = vec[i]; vec[i] = vec[j]; vec[j] = temp; } } // Cooley-Tukey decimation-in-time radix-2 FFT for (size_t size = 2; size <= n; size *= 2) { size_t halfsize = size / 2; size_t tablestep = n / size; for (size_t i = 0; i < n; i += size) { for (size_t j = i, k = 0; j < i + halfsize; j++, k += tablestep) { size_t l = j + halfsize; double complex temp = vec[l] * exptable[k]; vec[l] = vec[j] - temp; vec[j] += temp; } } if (size == n) // Prevent overflow in 'size *= 2' break; } FreeMemory((void *)exptable); return true; } /* @endcond */ void cmd_FFT(unsigned char *pp){ unsigned char *tp; PI = atan2(1, 1) * 4; #ifdef rp2350 int dims[MAXDIM]={0}; #else short dims[MAXDIM]={0}; #endif cplx *a1cplx=NULL, *a2cplx=NULL; MMFLOAT *a3float=NULL, *a4float=NULL, *a5float; int i, card1,card2, powerof2=0; tp = checkstring(pp, (unsigned char *)"MAGNITUDE"); if(tp) { getargs(&tp,3,(unsigned char *)","); card1=parsefloatrarray(argv[0],&a3float,1,1,dims, false); card2=parsefloatrarray(argv[2],&a4float,2,1,dims, true); if(card1 !=card2)error("Array size mismatch"); for(i=1;i<65536;i*=2){ if(card1==i)powerof2=1; } if(!powerof2)error("array size must be a power of 2"); a1cplx=(cplx *)GetTempMemory((card1)*16); a5float=(MMFLOAT *)a1cplx; for(i=0;i1.0)t=1.0; AHRSTimer=0; MadgwickQuaternionUpdate(ax, ay, az, gx, gy, gz, mx, my, mz, beta, t, pitch, yaw, roll); return; } if((p = checkstring((unsigned char *)passcmdline, (unsigned char *)"MAHONY")) != NULL) { getargs(&p, 27,(unsigned char *)","); if(argc < 23) error("Incorrect number of parameters"); MMFLOAT t; MMFLOAT *pitch, *yaw, *roll; MMFLOAT Kp, Ki; MMFLOAT ax; MMFLOAT ay; MMFLOAT az; MMFLOAT gx; MMFLOAT gy; MMFLOAT gz; MMFLOAT mx; MMFLOAT my; MMFLOAT mz; ax=getnumber(argv[0]); ay=getnumber(argv[2]); az=getnumber(argv[4]); gx=getnumber(argv[6]); gy=getnumber(argv[8]); gz=getnumber(argv[10]); mx=getnumber(argv[12]); my=getnumber(argv[14]); mz=getnumber(argv[16]); pitch = findvar(argv[18], V_FIND); if(!(g_vartbl[g_VarIndex].type & T_NBR)) error("Invalid variable"); roll = findvar(argv[20], V_FIND); if(!(g_vartbl[g_VarIndex].type & T_NBR)) error("Invalid variable"); yaw = findvar(argv[22], V_FIND); if(!(g_vartbl[g_VarIndex].type & T_NBR)) error("Invalid variable"); Kp=10.0 ; Ki=0.0; if(argc >= 25)Kp=getnumber(argv[24]); if(argc == 27)Ki=getnumber(argv[26]); t=(MMFLOAT)AHRSTimer/1000.0; if(t>1.0)t=1.0; AHRSTimer=0; MahonyQuaternionUpdate(ax, ay, az, gx, gy, gz, mx, my, mz, Ki, Kp, t, yaw, pitch, roll) ; return; } error("Invalid command"); } /* * @cond * The following section will be excluded from the documentation. */ void MadgwickQuaternionUpdate(MMFLOAT ax, MMFLOAT ay, MMFLOAT az, MMFLOAT gx, MMFLOAT gy, MMFLOAT gz, MMFLOAT mx, MMFLOAT my, MMFLOAT mz, MMFLOAT beta, MMFLOAT deltat, MMFLOAT *pitch, MMFLOAT *yaw, MMFLOAT *roll) { MMFLOAT q1 = q[0], q2 = q[1], q3 = q[2], q4 = q[3]; // short name local variable for readability MMFLOAT norm; MMFLOAT hx, hy, _2bx, _2bz; MMFLOAT s1, s2, s3, s4; MMFLOAT qDot1, qDot2, qDot3, qDot4; // Auxiliary variables to avoid repeated arithmetic MMFLOAT _2q1mx; MMFLOAT _2q1my; MMFLOAT _2q1mz; MMFLOAT _2q2mx; MMFLOAT _4bx; MMFLOAT _4bz; MMFLOAT _2q1 = 2.0 * q1; MMFLOAT _2q2 = 2.0 * q2; MMFLOAT _2q3 = 2.0 * q3; MMFLOAT _2q4 = 2.0 * q4; MMFLOAT _2q1q3 = 2.0 * q1 * q3; MMFLOAT _2q3q4 = 2.0 * q3 * q4; MMFLOAT q1q1 = q1 * q1; MMFLOAT q1q2 = q1 * q2; MMFLOAT q1q3 = q1 * q3; MMFLOAT q1q4 = q1 * q4; MMFLOAT q2q2 = q2 * q2; MMFLOAT q2q3 = q2 * q3; MMFLOAT q2q4 = q2 * q4; MMFLOAT q3q3 = q3 * q3; MMFLOAT q3q4 = q3 * q4; MMFLOAT q4q4 = q4 * q4; // Normalise accelerometer measurement norm = sqrt(ax * ax + ay * ay + az * az); if (norm == 0.0) return; // handle NaN norm = 1.0/norm; ax *= norm; ay *= norm; az *= norm; // Normalise magnetometer measurement norm = sqrt(mx * mx + my * my + mz * mz); if (norm == 0.0) return; // handle NaN norm = 1.0/norm; mx *= norm; my *= norm; mz *= norm; // Reference direction of Earth's magnetic field _2q1mx = 2.0 * q1 * mx; _2q1my = 2.0 * q1 * my; _2q1mz = 2.0 * q1 * mz; _2q2mx = 2.0 * q2 * mx; hx = mx * q1q1 - _2q1my * q4 + _2q1mz * q3 + mx * q2q2 + _2q2 * my * q3 + _2q2 * mz * q4 - mx * q3q3 - mx * q4q4; hy = _2q1mx * q4 + my * q1q1 - _2q1mz * q2 + _2q2mx * q3 - my * q2q2 + my * q3q3 + _2q3 * mz * q4 - my * q4q4; _2bx = sqrt(hx * hx + hy * hy); _2bz = -_2q1mx * q3 + _2q1my * q2 + mz * q1q1 + _2q2mx * q4 - mz * q2q2 + _2q3 * my * q4 - mz * q3q3 + mz * q4q4; _4bx = 2.0 * _2bx; _4bz = 2.0 * _2bz; // Gradient decent algorithm corrective step s1 = -_2q3 * (2.0 * q2q4 - _2q1q3 - ax) + _2q2 * (2.0 * q1q2 + _2q3q4 - ay) - _2bz * q3 * (_2bx * (0.5 - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx) + (-_2bx * q4 + _2bz * q2) * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my) + _2bx * q3 * (_2bx * (q1q3 + q2q4) + _2bz * (0.5 - q2q2 - q3q3) - mz); s2 = _2q4 * (2.0 * q2q4 - _2q1q3 - ax) + _2q1 * (2.0 * q1q2 + _2q3q4 - ay) - 4.0 * q2 * (1.0 - 2.0 * q2q2 - 2.0 * q3q3 - az) + _2bz * q4 * (_2bx * (0.5 - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx) + (_2bx * q3 + _2bz * q1) * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my) + (_2bx * q4 - _4bz * q2) * (_2bx * (q1q3 + q2q4) + _2bz * (0.5 - q2q2 - q3q3) - mz); s3 = -_2q1 * (2.0 * q2q4 - _2q1q3 - ax) + _2q4 * (2.0 * q1q2 + _2q3q4 - ay) - 4.0 * q3 * (1.0 - 2.0 * q2q2 - 2.0 * q3q3 - az) + (-_4bx * q3 - _2bz * q1) * (_2bx * (0.5 - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx) + (_2bx * q2 + _2bz * q4) * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my) + (_2bx * q1 - _4bz * q3) * (_2bx * (q1q3 + q2q4) + _2bz * (0.5 - q2q2 - q3q3) - mz); s4 = _2q2 * (2.0 * q2q4 - _2q1q3 - ax) + _2q3 * (2.0 * q1q2 + _2q3q4 - ay) + (-_4bx * q4 + _2bz * q2) * (_2bx * (0.5 - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx) + (-_2bx * q1 + _2bz * q3) * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my) + _2bx * q2 * (_2bx * (q1q3 + q2q4) + _2bz * (0.5 - q2q2 - q3q3) - mz); norm = sqrt(s1 * s1 + s2 * s2 + s3 * s3 + s4 * s4); // normalise step magnitude norm = 1.0/norm; s1 *= norm; s2 *= norm; s3 *= norm; s4 *= norm; // Compute rate of change of quaternion qDot1 = 0.5 * (-q2 * gx - q3 * gy - q4 * gz) - beta * s1; qDot2 = 0.5 * (q1 * gx + q3 * gz - q4 * gy) - beta * s2; qDot3 = 0.5 * (q1 * gy - q2 * gz + q4 * gx) - beta * s3; qDot4 = 0.5 * (q1 * gz + q2 * gy - q3 * gx) - beta * s4; // Integrate to yield quaternion q1 += qDot1 * deltat; q2 += qDot2 * deltat; q3 += qDot3 * deltat; q4 += qDot4 * deltat; norm = sqrt(q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4); // normalise quaternion norm = 1.0/norm; q[0] = q1 * norm; q[1] = q2 * norm; q[2] = q3 * norm; q[3] = q4 * norm; MMFLOAT ysqr = q3 * q3; // roll (x-axis rotation) MMFLOAT t0 = +2.0 * (q1 * q2 + q3 * q4); MMFLOAT t1 = +1.0 - 2.0 * (q2 * q2 + ysqr); *roll = atan2(t0, t1); // pitch (y-axis rotation) MMFLOAT t2 = +2.0 * (q1 * q3 - q4 * q2); t2 = t2 > 1.0 ? 1.0 : t2; t2 = t2 < -1.0 ? -1.0 : t2; *pitch = asin(t2); // yaw (z-axis rotation) MMFLOAT t3 = +2.0 * (q1 * q4 + q2 *q3); MMFLOAT t4 = +1.0 - 2.0 * (ysqr + q4 * q4); *yaw = atan2(t3, t4); } void MahonyQuaternionUpdate(MMFLOAT ax, MMFLOAT ay, MMFLOAT az, MMFLOAT gx, MMFLOAT gy, MMFLOAT gz, MMFLOAT mx, MMFLOAT my, MMFLOAT mz, MMFLOAT Ki, MMFLOAT Kp, MMFLOAT deltat, MMFLOAT *yaw, MMFLOAT *pitch, MMFLOAT *roll) { MMFLOAT q1 = q[0], q2 = q[1], q3 = q[2], q4 = q[3]; // short name local variable for readability MMFLOAT norm; MMFLOAT hx, hy, bx, bz; MMFLOAT vx, vy, vz, wx, wy, wz; MMFLOAT ex, ey, ez; MMFLOAT pa, pb, pc; // Auxiliary variables to avoid repeated arithmetic MMFLOAT q1q1 = q1 * q1; MMFLOAT q1q2 = q1 * q2; MMFLOAT q1q3 = q1 * q3; MMFLOAT q1q4 = q1 * q4; MMFLOAT q2q2 = q2 * q2; MMFLOAT q2q3 = q2 * q3; MMFLOAT q2q4 = q2 * q4; MMFLOAT q3q3 = q3 * q3; MMFLOAT q3q4 = q3 * q4; MMFLOAT q4q4 = q4 * q4; // Normalise accelerometer measurement norm = sqrt(ax * ax + ay * ay + az * az); if (norm == 0.0) return; // handle NaN norm = 1.0 / norm; // use reciprocal for division ax *= norm; ay *= norm; az *= norm; // Normalise magnetometer measurement norm = sqrt(mx * mx + my * my + mz * mz); if (norm == 0.0) return; // handle NaN norm = 1.0 / norm; // use reciprocal for division mx *= norm; my *= norm; mz *= norm; // Reference direction of Earth's magnetic field hx = 2.0 * mx * (0.5 - q3q3 - q4q4) + 2.0 * my * (q2q3 - q1q4) + 2.0 * mz * (q2q4 + q1q3); hy = 2.0 * mx * (q2q3 + q1q4) + 2.0 * my * (0.5 - q2q2 - q4q4) + 2.0 * mz * (q3q4 - q1q2); bx = sqrt((hx * hx) + (hy * hy)); bz = 2.0 * mx * (q2q4 - q1q3) + 2.0 * my * (q3q4 + q1q2) + 2.0 * mz * (0.5 - q2q2 - q3q3); // Estimated direction of gravity and magnetic field vx = 2.0 * (q2q4 - q1q3); vy = 2.0 * (q1q2 + q3q4); vz = q1q1 - q2q2 - q3q3 + q4q4; wx = 2.0 * bx * (0.5 - q3q3 - q4q4) + 2.0 * bz * (q2q4 - q1q3); wy = 2.0 * bx * (q2q3 - q1q4) + 2.0 * bz * (q1q2 + q3q4); wz = 2.0 * bx * (q1q3 + q2q4) + 2.0 * bz * (0.5 - q2q2 - q3q3); // Error is cross product between estimated direction and measured direction of gravity ex = (ay * vz - az * vy) + (my * wz - mz * wy); ey = (az * vx - ax * vz) + (mz * wx - mx * wz); ez = (ax * vy - ay * vx) + (mx * wy - my * wx); if (Ki > 0.0) { eInt[0] += ex; // accumulate integral error eInt[1] += ey; eInt[2] += ez; } else { eInt[0] = 0.0; // prevent integral wind up eInt[1] = 0.0; eInt[2] = 0.0; } // Apply feedback terms gx = gx + Kp * ex + Ki * eInt[0]; gy = gy + Kp * ey + Ki * eInt[1]; gz = gz + Kp * ez + Ki * eInt[2]; // Integrate rate of change of quaternion pa = q2; pb = q3; pc = q4; q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5 * deltat); q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5 * deltat); q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5 * deltat); q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5 * deltat); // Normalise quaternion norm = sqrt(q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4); norm = 1.0 / norm; q[0] = q1 * norm; q[1] = q2 * norm; q[2] = q3 * norm; q[3] = q4 * norm; MMFLOAT ysqr = q3 * q3; // roll (x-axis rotation) MMFLOAT t0 = +2.0 * (q1 * q2 + q3 * q4); MMFLOAT t1 = +1.0 - 2.0 * (q2 * q2 + ysqr); *roll = atan2(t0, t1); // pitch (y-axis rotation) MMFLOAT t2 = +2.0 * (q1 * q3 - q4 * q2); t2 = t2 > 1.0 ? 1.0 : t2; t2 = t2 < -1.0 ? -1.0 : t2; *pitch = asin(t2); // yaw (z-axis rotation) MMFLOAT t3 = +2.0 * (q1 * q4 + q2 *q3); MMFLOAT t4 = +1.0 - 2.0 * (ysqr + q4 * q4); *yaw = atan2(t3, t4); } /*Finding transpose of cofactor of matrix*/ void transpose(MMFLOAT **matrix,MMFLOAT **matrix_cofactor,MMFLOAT **newmatrix, int size) { int i,j; MMFLOAT d; MMFLOAT **m_transpose=alloc2df(size,size); MMFLOAT **m_inverse=alloc2df(size,size); for (i=0;i