diff --git a/Makefile b/Makefile index 644594b..822d38b 100644 --- a/Makefile +++ b/Makefile @@ -12,9 +12,9 @@ OPT_LEVEL = -Os # -------------------------- VERSION NUMBER ------------------------- # software version -SW_VER_MAJOR = 0 +SW_VER_MAJOR = 1 SW_VER_MINOR = 0 -SW_VER_BUILD = 1 +SW_VER_BUILD = 0 # hardware version HW_VER_MAJOR = 1 @@ -35,7 +35,10 @@ SRC += ./at/src/ntf.c SRC += ./at/cmd/src/gen.c ./at/cmd/src/radio.c # at protocol notification submodules -SRC += ./at/ntf/src/debug.c +SRC += ./at/ntf/src/debug.c ./at/ntf/src/radio.c + +# base64 encoder-decoder +SRC += ./base64/src/base64.c # device drivers SRC += ./dev/src/usart2.c ./dev/src/watchdog.c diff --git a/README.md b/README.md index 87bed18..47cc496 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,24 @@ # stm32l476-radio-receiver -All on-board digital AM radio receiver implemented on the stm32l4discovery board. No external components needed. Well maybe besides the looooong antenna wire. +All digital AM radio receiver implemented on the stm32l4-discovery board. All the information is here: +https://mightydevices.com/index.php/2020/02/stm32l4-discovery-radio-receiver/ -## Principle of operation - -TODO - -## Makefile - -This project can be build using gcc or llvm (clang). This is how the Makefile and the linker script was prepared. Makefile is GNUMake compatible. You can configure all the tools used for building, add sources, libraries, etc.. ## How to build +This project can be build using arm-none-eabi-gcc. This is how the Makefile and the linker script were prepared for. Makefile is GNUMake compatible. + Two things are needed: -* Toolchain that contains C compiler, linker and supporting tools (like objcopy, objdump, nm, size) may be gcc arm embedded toolchain or clang/llvm equivalents with libraries such as libc, libg, libm or whatever you may require +* Toolchain that contains C compiler, like the one from developer.arm.com * GNUMake to 'execute' the Makefile -Building using GCC: -``` -make TOOLCHAIN=gcc all +If you into dockerization then please read: https://mightydevices.com/index.php/2019/09/stm32-development-env-for-windows-vscode-arm-gcc-toolchain-openocd/ + + +Building command: ``` -Builing using LLVM: +make all ``` -make TOOLCHAIN=llvm all -``` \ No newline at end of file + +The firmware will be put into `./outs` directory \ No newline at end of file diff --git a/at/ntf.h b/at/ntf.h index 43b8421..42324fc 100644 --- a/at/ntf.h +++ b/at/ntf.h @@ -19,8 +19,8 @@ /** @{ */ /** @brief debug notifications */ #define AT_NTF_MASK_DEBUG (0x00000001) -/** @brief radio data notifications */ -#define AT_NTF_MASK_RADIO_DATA (0x00000002) +/** @brief radio iq samples */ +#define AT_NTF_MASK_RADIO_IQ (0x00000002) /** @} */ /** @} */ @@ -37,13 +37,6 @@ int ATNtf_Init(void); */ void ATNtf_Poll(void); -/** - * @brief This function shall invoke the notification data drainage, which will in - * turn produce notification strings and try to put them within the output buffer. To - * be called by the ATRxTx drivers at the end of transmission. - */ -void ATNtf_DrainData(void); - /** * @brief Sets the notification mask, enabling or disabling the notifications on * selected interface. diff --git a/at/ntf/radio.h b/at/ntf/radio.h new file mode 100644 index 0000000..a642855 --- /dev/null +++ b/at/ntf/radio.h @@ -0,0 +1,21 @@ +/** + * @file radio.h + * + * @date 2020-02-05 + * @author twatorowski + * + * @brief AT Notifications: Radio. + */ + +#ifndef AT_NTF_RADIO_H +#define AT_NTF_RADIO_H + + +/* initialize radio notifications submodule */ +int ATNtfRadio_Init(void); +/* poll radio notifications submodule */ +void ATNtfRadio_Poll(void); +/* store the iq data samples in at notifications buffer */ +int ATNtfRadio_PutIQSamples(const float *i, const float *q, int num); + +#endif /* AT_NTF_RADIO_H */ diff --git a/at/ntf/src/radio.c b/at/ntf/src/radio.c index 3cacdb8..ed71939 100644 --- a/at/ntf/src/radio.c +++ b/at/ntf/src/radio.c @@ -10,47 +10,126 @@ #include #include +#include "compiler.h" +#include "config.h" #include "err.h" -#include "at/ntfy.h" +#include "at/ntf.h" #include "at/rxtx.h" +#include "base64/base64.h" +#include "util/elems.h" +#include "util/minmax.h" +#include "util/string.h" /* iqdata buffer */ static struct iqdata { /* samples buffer */ - float buf[128]; + struct iqdata_iq { float i, q; } PACKED ALIGNED(8) buf[128]; /* pointers */ uint32_t head, tail; } iqdata; +/* polling for the iq samples */ +static void ATNtfRadio_IQSamplesPoll(void) +{ + /* data sent? */ + int sent = 0; + /* response buffer */ + char buf[AT_RES_MAX_LINE_LEN] = "+RADIO_IQ: "; + /* current len of the response */ + int len = sizeof("+RADIO_IQ: ") - 1; + + /* notification mask */ + uint32_t mask; + /* get mask for all notifications */ + ATNtf_GetNotificationORMask(&mask); + /* notification is disabled? */ + if (!(mask & AT_NTF_MASK_RADIO_IQ)) + iqdata.tail = iqdata.head; + /* no samples are stored */ + if (iqdata.head - iqdata.tail < 16) + return; + + /* get the number data characters that can be put into the response */ + int max_chars = sizeof(buf) - len - sizeof(AT_LINE_END); + /* convert to maximal number of representable bytes when base64 is used */ + int max_bytes = (max_chars / 4) * 3; + /* get tail index */ + int t = iqdata.tail % elems(iqdata.buf); + /* limit the number of iq pairs to be sent in current line while not + * wrapping within the circular buffer */ + int max_iqs = min(iqdata.head - iqdata.tail, + min(elems(iqdata.buf) - t, max_bytes / sizeof(struct iqdata_iq))); + + /* encode data in base64 */ + int b64_len = Base64_Encode(iqdata.buf + t, + sizeof(struct iqdata_iq) * max_iqs, buf + len, max_chars); + /* append the line ending sequence */ + memcpy(buf + len + b64_len, AT_LINE_END, sizeof(AT_LINE_END)); + + /* send response */ + for (int iface = 0; iface < ATRXTX_IFACENUM; iface++) { + /* get notification mask for given interface */ + ATNtf_GetNotificationMask(iface, &mask); + /* notifications enabled for given interface? */ + if ((mask & AT_NTF_MASK_RADIO_IQ)) { + /* send the actual data */ + sent |= ATRxTx_SendResponse(iface, 1, buf, len + b64_len + + sizeof(AT_LINE_END) - 1) == EOK; + } + } + + /* data was sent, update the buffer */ + if (sent) + iqdata.tail += max_iqs; +} /* initialize radio notifications submodule */ -int ATNtfyRadio_Init(void) +int ATNtfRadio_Init(void) { /* report status */ return EOK; } /* poll radio notifications submodule */ -void ATNtfyRadio_Poll(void) +void ATNtfRadio_Poll(void) { - + /* polling for the iq samples */ + ATNtfRadio_IQSamplesPoll(); } /* store the iq data samples in at notifications buffer */ -int ATRadio_PutIQsamples(const float *i, const float *q, int num) +int ATNtfRadio_PutIQSamples(const float *i, const float *q, int num) { - /* data stored? */ - int sent = 0; /* notification mask placeholder */ uint32_t mask; /* get mask for all notifications */ - ATNtfy_GetNotificationORMask(&mask); - /* this is to avoid stalling debugs when no interface has enabled - * debug logic */ - if (!(mask & AT_NTFY_MASK_RADIO_DATA)) + ATNtf_GetNotificationORMask(&mask); + /* radio data notifications enabled? */ + if (!(mask & AT_NTF_MASK_RADIO_IQ)) return EOK; + /* no space in buffer */ + if (num > elems(iqdata.buf) - (iqdata.head - iqdata.tail)) + return EFATAL; + + /* head element index */ + int h = iqdata.head % elems(iqdata.buf); + /* number of elements to be stored before wrapping */ + int bwrap = min(num, elems(iqdata.buf) - h); + /* number of elements to be stored after wrapping */ + int awrap = num - bwrap; + + /* store before wrapping */ + for (; bwrap ; bwrap--, h++) { + iqdata.buf[h].i = *i++; iqdata.buf[h].q = *q++; + } + /* store after wrapping */ + for (h = 0; awrap; awrap--, h++) { + iqdata.buf[h].i = *i++; iqdata.buf[h].q = *q++; + } + /* update the head pointer */ + iqdata.head += num; /* report status */ - return sent ? EOK : EFATAL; + return EOK; } \ No newline at end of file diff --git a/at/src/ntf.c b/at/src/ntf.c index 727e418..0dabf04 100644 --- a/at/src/ntf.c +++ b/at/src/ntf.c @@ -17,6 +17,7 @@ /* submodules */ #include "at/ntf/debug.h" +#include "at/ntf/radio.h" /* notification mask */ static uint32_t ntf_mask[ATRXTX_IFACENUM] = { @@ -34,6 +35,7 @@ int ATNtf_Init(void) /* initialize all notification submodules */ rc |= ATNtfDebug_Init(); + rc |= ATNtfRadio_Init(); /* report status */ return EOK; @@ -45,6 +47,7 @@ void ATNtf_Poll(void) /* poll all notification submodules */ /* debug */ ATNtfDebug_Poll(); + ATNtfRadio_Poll(); } /* set notification mask */ diff --git a/at/src/rxtx_usart2.c b/at/src/rxtx_usart2.c index 6c048a1..0be80cb 100644 --- a/at/src/rxtx_usart2.c +++ b/at/src/rxtx_usart2.c @@ -28,7 +28,7 @@ static volatile uint32_t rx_buf_offs, tx_head, tx_head_alloc, tx_tail; static uint8_t rx_buf[512 + 32], tx_buf[2048]; /* usart transmission complete callback */ -static int ATRxTxUSART2_USART1TxCallback(void *ptr) +static int ATRxTxUSART2_USART2TxCallback(void *ptr) { /* callback argument */ usart2_cbarg_t *arg = ptr; @@ -53,7 +53,7 @@ static int ATRxTxUSART2_USART1TxCallback(void *ptr) /* limit to the number of bytes buffered */ bytes_wrap = min(bytes_wrap, bytes_buffered); /* send the data */ - USART2_Send(tx_buf + tail, bytes_wrap, ATRxTxUSART2_USART1TxCallback); + USART2_Send(tx_buf + tail, bytes_wrap, ATRxTxUSART2_USART2TxCallback); } /* report status */ @@ -109,7 +109,7 @@ int ATRxTxUSART2_Init(void) { /* lock the reception semaphore and start reception */ Sem_Lock(&usart2rx_sem, ATRxTxUSART2_USART1RxCallback); - Sem_Lock(&usart2tx_sem, ATRxTxUSART2_USART1TxCallback); + Sem_Lock(&usart2tx_sem, ATRxTxUSART2_USART2TxCallback); /* report status */ return EOK; } @@ -159,7 +159,7 @@ int ATRxTxUSART2_SendResponse(int is_notify, const char *str, size_t len) Atomic_MOV32(&tx_head, &tx_head_alloc); /* restart transmission */ if (Sem_Lock(&usart2tx_sem, CB_NONE) == EOK) - ATRxTxUSART2_USART1TxCallback(0); + ATRxTxUSART2_USART2TxCallback(0); } /* report success */ diff --git a/base64/base64.h b/base64/base64.h new file mode 100644 index 0000000..b09695c --- /dev/null +++ b/base64/base64.h @@ -0,0 +1,43 @@ +/** + * @file base64.h + * + * @date 2019-11-27 + * @author twatorowski + * + * @brief Base64 encoding/decoding functions. + */ + +#ifndef BASE64_BASE64_H_ +#define BASE64_BASE64_H_ + +#include + +/* encode with base64 */ + +/** + * @brief Encode the input data with Base64 encoding. The algorithm works + * backwards to make the in-situ operation possible if needed. + * + * @param in input data pointer + * @param in_size size of the input data + * @param out output data pointer + * @param out_size maximal size of the output buffer + * + * @return int actual encoded data size + */ +int Base64_Encode(const void *in, size_t in_size, void *out, size_t out_size); +/* decode base64 string */ + +/** + * @brief Decode the provided Base64 string. Can work in-situ. + * + * @param in pointer to Base64 encoded data + * @param in_size size of the input data + * @param out + * @param out_size + * + * @return int + */ +int Base64_Decode(const void *in, size_t in_size, void *out, size_t out_size); + +#endif /* BASE64_BASE64_H_ */ diff --git a/base64/src/base64.c b/base64/src/base64.c new file mode 100644 index 0000000..ef67c9c --- /dev/null +++ b/base64/src/base64.c @@ -0,0 +1,127 @@ +/** + * @file base64.c + * + * @date 2019-11-27 + * @author twatorowski + * + * @brief Base64 encoding/decoding functions. + */ + +#include +#include + +#include "compiler.h" +#include "err.h" + +/* encoding */ +static const uint8_t enc[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' +}; + +/* decoder array (offset by '+') */ +static const uint8_t dec[] = { + 62, 64, 64, 64, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, + 64, 64, 0, 64, 64, 64, 0, 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, + 64, 64, 64, 64, 64, 64, 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, +}; + +/* encode with base64 */ +int OPTIMIZE("Os") Base64_Encode(const void *in, size_t in_size, void *out, + size_t out_size) +{ + /* number of whole words to process. word is a register that holds 24 bits + * of input data that we are about to convert to base 64 representation */ + int word_cnt = (in_size + 2) / 3; + /* number of bytes that do not constitute the full word */ + int remainder = in_size % 3; + /* move the input pointer so that it points at last valid 24-word of data */ + const uint8_t *inp = (const uint8_t *)in + (word_cnt - 1) * 3; + /* output pointer shall point at last word to be written */ + uint8_t *outp = (uint8_t *)out + (word_cnt - 1) * 4; + /* packing register */ + register uint32_t value; + + /* sanity check for the output/input size */ + if (word_cnt * 4 > out_size || !in_size) + return EFATAL; + + /* got remaining data to pack? */ + if (remainder) { + /* pack last remaining bytes */ + value = inp[0] << 16 | (remainder > 1 ? inp[1] << 8 : 0); + /* at least two charactes must be produced */ + outp[0] = enc[(value >> 18) & 0x3f]; + outp[1] = enc[(value >> 12) & 0x3f]; + /* trailing '=' go here */ + outp[2] = remainder > 1 ? enc[(value >> 6) & 0x3f] : '='; + outp[3] = '='; + /* adjust pointers */ + inp -= 3, outp -= 4; + } + + /* pack the data backwards */ + for (; (uintptr_t)inp >= (uintptr_t)in; inp -= 3, outp -= 4) { + /* pack value */ + value = inp[0] << 16 | inp[1] << 8 | inp[2] << 0; + /* encode */ + outp[0] = enc[(value >> 18) & 0x3f]; + outp[1] = enc[(value >> 12) & 0x3f]; + outp[2] = enc[(value >> 6) & 0x3f]; + outp[3] = enc[(value >> 0) & 0x3f]; + } + + /* return the number of bytes written */ + return word_cnt * 4; +} + +/* decode base 64-string */ +int OPTIMIZE("Os") Base64_Decode(const void *in, size_t in_size, void *out, + size_t out_size) +{ + /* number of base64 4-character words */ + int word_cnt = in_size / 4, remainder = in_size % 4; + /* last word may be incomplete (trailing '=') */ + int last_word_len = 3; + /* pointers */ + const uint8_t *inp = in; uint8_t *outp = out; + /* packing register */ + register uint32_t value; + + /* '=' is a trailing character? */ + if (*(inp + in_size - 1) == '=') last_word_len--; + if (*(inp + in_size - 2) == '=') last_word_len--; + /* size sanity checks */ + if (!in_size || remainder || out_size < (word_cnt-1) * 3 + last_word_len) + return EFATAL; + + /* process all but last word */ + while (1) { + /* decode */ + value = dec[*inp++ - '+'] << 18; + value |= dec[*inp++ - '+'] << 12; + value |= dec[*inp++ - '+'] << 6; + value |= dec[*inp++ - '+'] << 0; + /* break the loop on the last word */ + if (word_cnt-- <= 1) + break; + /* unpack */ + *outp++ = value >> 16, *outp++ = value >> 8, *outp++ = value >> 0; + } + + /* '=' are automatically decoded as zeros */ + if (last_word_len > 0) *outp++ = value >> 16; + if (last_word_len > 1) *outp++ = value >> 8; + if (last_word_len > 2) *outp++ = value >> 0; + + /* report the number of bytes */ + return outp - (uint8_t *)out; +} diff --git a/config.h b/config.h index 4c93b6e..68ffa1a 100644 --- a/config.h +++ b/config.h @@ -96,7 +96,7 @@ /** @name USART2 configuration */ /** @{ */ /** @brief usart baudrate */ -#define USART2_BAUD_RATE 2000000 +#define USART2_BAUD_RATE 1500000 /** @} */ /** @name IQ Decimators */ diff --git a/dev/src/usart2.c b/dev/src/usart2.c index 08c008e..f5912a1 100644 --- a/dev/src/usart2.c +++ b/dev/src/usart2.c @@ -34,7 +34,7 @@ static uint8_t *rx_ptr; /* buffer size */ static size_t rx_size, tx_size; /* callback */ -static cb_t rx_cb, tx_cb; +static volatile cb_t rx_cb, tx_cb; /* callback arguments */ static usart2_cbarg_t rx_cb_arg, tx_cb_arg; @@ -129,14 +129,14 @@ static void USART2_USART2IdleIsr(void) void USART2_USART2Isr(void) { /* get status register, mask out unused interrupts */ - uint32_t sr = USART2->ISR & USART2->CR1 & (USART_ISR_TC | USART_ISR_IDLE); + uint32_t sr = USART2->ISR, cr = USART2->CR1; /* transfer complete */ - if (sr & USART_ISR_TC) + if ((sr & USART_ISR_TC) && (cr & USART_CR1_TCIE)) USART2_USART2TransferCompleteIsr(); /* idle state detected */ - if (sr & USART_ISR_IDLE) + if ((sr & USART_ISR_IDLE) && (cr & USART_CR1_IDLEIE)) USART2_USART2IdleIsr(); } @@ -173,7 +173,7 @@ int USART2_Init(void) RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN; /* enable gpiod */ RCC->AHB2ENR |= RCC_AHB2ENR_GPIODEN; - /* enable usart1 clock */ + /* enable usart2 clock */ RCC->APB1ENR1 |= RCC_APB1ENR1_USART2EN; /* reset usart */ diff --git a/main.c b/main.c index 9c917fe..7057f15 100644 --- a/main.c +++ b/main.c @@ -39,6 +39,10 @@ #define DEBUG #include "debug.h" +static int U2(void *ptr) +{ + USART2_Send("!RADIO_IQ: napis testowy smaczny i zdrowy\r\n", 43, U2); +} /* program init function, called before main with interrupts disabled */ void Init(void) @@ -115,11 +119,13 @@ void Main(void) /* test dynamic interrupt levels */ // TestDynInt_Init(); + // U2(0); /* execution loop */ while (1) { /* poll at protocol routines */ AT_Poll(); + /* kick the dog counter */ diff --git a/radio/src/mix2.c b/radio/src/mix2.c index 89aa6d8..4a1be70 100644 --- a/radio/src/mix2.c +++ b/radio/src/mix2.c @@ -20,74 +20,264 @@ /* cosine look up table */ static const float cos_lut[] = { - +0x1.000000p+0, +0x1.ffd886p-1, +0x1.ff621ep-1, +0x1.fe9cdap-1, - +0x1.fd88dap-1, +0x1.fc2648p-1, +0x1.fa7558p-1, +0x1.f87650p-1, - +0x1.f6297cp-1, +0x1.f38f3ap-1, +0x1.f0a7f0p-1, +0x1.ed740ep-1, - +0x1.e9f416p-1, +0x1.e6288ep-1, +0x1.e21210p-1, +0x1.ddb13cp-1, - +0x1.d906bcp-1, +0x1.d4134ep-1, +0x1.ced7b0p-1, +0x1.c954b2p-1, - +0x1.c38b30p-1, +0x1.bd7c0ap-1, +0x1.b72834p-1, +0x1.b090a6p-1, - +0x1.a9b662p-1, +0x1.a29a7ap-1, +0x1.9b3e04p-1, +0x1.93a224p-1, - +0x1.8bc806p-1, +0x1.83b0e0p-1, +0x1.7b5df2p-1, +0x1.72d084p-1, - +0x1.6a09e6p-1, +0x1.610b76p-1, +0x1.57d694p-1, +0x1.4e6cacp-1, - +0x1.44cf32p-1, +0x1.3affa2p-1, +0x1.30ff80p-1, +0x1.26d054p-1, - +0x1.1c73b4p-1, +0x1.11eb36p-1, +0x1.07387ap-1, +0x1.f8ba4ep-2, - +0x1.e2b5d4p-2, +0x1.cc66eap-2, +0x1.b5d100p-2, +0x1.9ef794p-2, - +0x1.87de2ap-2, +0x1.708854p-2, +0x1.58f9a8p-2, +0x1.4135cap-2, - +0x1.294062p-2, +0x1.111d26p-2, +0x1.f19f98p-3, +0x1.c0b826p-3, - +0x1.8f8b84p-3, +0x1.5e2144p-3, +0x1.2c8106p-3, +0x1.f564e6p-4, - +0x1.917a6cp-4, +0x1.2d520ap-4, +0x1.91f660p-5, +0x1.921560p-6, - +0x0.000000p-0, -0x1.921560p-6, -0x1.91f660p-5, -0x1.2d520ap-4, - -0x1.917a6cp-4, -0x1.f564e6p-4, -0x1.2c8106p-3, -0x1.5e2144p-3, - -0x1.8f8b84p-3, -0x1.c0b826p-3, -0x1.f19f98p-3, -0x1.111d26p-2, - -0x1.294062p-2, -0x1.4135cap-2, -0x1.58f9a8p-2, -0x1.708854p-2, - -0x1.87de2ap-2, -0x1.9ef794p-2, -0x1.b5d100p-2, -0x1.cc66eap-2, - -0x1.e2b5d4p-2, -0x1.f8ba4ep-2, -0x1.07387ap-1, -0x1.11eb36p-1, - -0x1.1c73b4p-1, -0x1.26d054p-1, -0x1.30ff80p-1, -0x1.3affa2p-1, - -0x1.44cf32p-1, -0x1.4e6cacp-1, -0x1.57d694p-1, -0x1.610b76p-1, - -0x1.6a09e6p-1, -0x1.72d084p-1, -0x1.7b5df2p-1, -0x1.83b0e0p-1, - -0x1.8bc806p-1, -0x1.93a224p-1, -0x1.9b3e04p-1, -0x1.a29a7ap-1, - -0x1.a9b662p-1, -0x1.b090a6p-1, -0x1.b72834p-1, -0x1.bd7c0ap-1, - -0x1.c38b30p-1, -0x1.c954b2p-1, -0x1.ced7b0p-1, -0x1.d4134ep-1, - -0x1.d906bcp-1, -0x1.ddb13cp-1, -0x1.e21210p-1, -0x1.e6288ep-1, - -0x1.e9f416p-1, -0x1.ed740ep-1, -0x1.f0a7f0p-1, -0x1.f38f3ap-1, - -0x1.f6297cp-1, -0x1.f87650p-1, -0x1.fa7558p-1, -0x1.fc2648p-1, - -0x1.fd88dap-1, -0x1.fe9cdap-1, -0x1.ff621ep-1, -0x1.ffd886p-1, - -0x1.000000p+0, -0x1.ffd886p-1, -0x1.ff621ep-1, -0x1.fe9cdap-1, - -0x1.fd88dap-1, -0x1.fc2648p-1, -0x1.fa7558p-1, -0x1.f87650p-1, - -0x1.f6297cp-1, -0x1.f38f3ap-1, -0x1.f0a7f0p-1, -0x1.ed740ep-1, - -0x1.e9f416p-1, -0x1.e6288ep-1, -0x1.e21210p-1, -0x1.ddb13cp-1, - -0x1.d906bcp-1, -0x1.d4134ep-1, -0x1.ced7b0p-1, -0x1.c954b2p-1, - -0x1.c38b30p-1, -0x1.bd7c0ap-1, -0x1.b72834p-1, -0x1.b090a6p-1, - -0x1.a9b662p-1, -0x1.a29a7ap-1, -0x1.9b3e04p-1, -0x1.93a224p-1, - -0x1.8bc806p-1, -0x1.83b0e0p-1, -0x1.7b5df2p-1, -0x1.72d084p-1, - -0x1.6a09e6p-1, -0x1.610b76p-1, -0x1.57d694p-1, -0x1.4e6cacp-1, - -0x1.44cf32p-1, -0x1.3affa2p-1, -0x1.30ff80p-1, -0x1.26d054p-1, - -0x1.1c73b4p-1, -0x1.11eb36p-1, -0x1.07387ap-1, -0x1.f8ba4ep-2, - -0x1.e2b5d4p-2, -0x1.cc66eap-2, -0x1.b5d100p-2, -0x1.9ef794p-2, - -0x1.87de2ap-2, -0x1.708854p-2, -0x1.58f9a8p-2, -0x1.4135cap-2, - -0x1.294062p-2, -0x1.111d26p-2, -0x1.f19f98p-3, -0x1.c0b826p-3, - -0x1.8f8b84p-3, -0x1.5e2144p-3, -0x1.2c8106p-3, -0x1.f564e6p-4, - -0x1.917a6cp-4, -0x1.2d520ap-4, -0x1.91f660p-5, -0x1.921560p-6, - -0x0.000000p-0, +0x1.921560p-6, +0x1.91f660p-5, +0x1.2d520ap-4, - +0x1.917a6cp-4, +0x1.f564e6p-4, +0x1.2c8106p-3, +0x1.5e2144p-3, - +0x1.8f8b84p-3, +0x1.c0b826p-3, +0x1.f19f98p-3, +0x1.111d26p-2, - +0x1.294062p-2, +0x1.4135cap-2, +0x1.58f9a8p-2, +0x1.708854p-2, - +0x1.87de2ap-2, +0x1.9ef794p-2, +0x1.b5d100p-2, +0x1.cc66eap-2, - +0x1.e2b5d4p-2, +0x1.f8ba4ep-2, +0x1.07387ap-1, +0x1.11eb36p-1, - +0x1.1c73b4p-1, +0x1.26d054p-1, +0x1.30ff80p-1, +0x1.3affa2p-1, - +0x1.44cf32p-1, +0x1.4e6cacp-1, +0x1.57d694p-1, +0x1.610b76p-1, - +0x1.6a09e6p-1, +0x1.72d084p-1, +0x1.7b5df2p-1, +0x1.83b0e0p-1, - +0x1.8bc806p-1, +0x1.93a224p-1, +0x1.9b3e04p-1, +0x1.a29a7ap-1, - +0x1.a9b662p-1, +0x1.b090a6p-1, +0x1.b72834p-1, +0x1.bd7c0ap-1, - +0x1.c38b30p-1, +0x1.c954b2p-1, +0x1.ced7b0p-1, +0x1.d4134ep-1, - +0x1.d906bcp-1, +0x1.ddb13cp-1, +0x1.e21210p-1, +0x1.e6288ep-1, - +0x1.e9f416p-1, +0x1.ed740ep-1, +0x1.f0a7f0p-1, +0x1.f38f3ap-1, - +0x1.f6297cp-1, +0x1.f87650p-1, +0x1.fa7558p-1, +0x1.fc2648p-1, - +0x1.fd88dap-1, +0x1.fe9cdap-1, +0x1.ff621ep-1, +0x1.ffd886p-1, + +1.000000e+00, +9.999812e-01, +9.999247e-01, +9.998306e-01, + +9.996988e-01, +9.995294e-01, +9.993224e-01, +9.990777e-01, + +9.987955e-01, +9.984756e-01, +9.981181e-01, +9.977231e-01, + +9.972905e-01, +9.968203e-01, +9.963126e-01, +9.957674e-01, + +9.951847e-01, +9.945646e-01, +9.939070e-01, +9.932119e-01, + +9.924795e-01, +9.917098e-01, +9.909026e-01, +9.900582e-01, + +9.891765e-01, +9.882576e-01, +9.873014e-01, +9.863081e-01, + +9.852776e-01, +9.842101e-01, +9.831055e-01, +9.819639e-01, + +9.807853e-01, +9.795698e-01, +9.783174e-01, +9.770281e-01, + +9.757021e-01, +9.743394e-01, +9.729400e-01, +9.715039e-01, + +9.700313e-01, +9.685221e-01, +9.669765e-01, +9.653944e-01, + +9.637761e-01, +9.621214e-01, +9.604305e-01, +9.587035e-01, + +9.569403e-01, +9.551412e-01, +9.533060e-01, +9.514350e-01, + +9.495282e-01, +9.475856e-01, +9.456073e-01, +9.435935e-01, + +9.415441e-01, +9.394592e-01, +9.373390e-01, +9.351835e-01, + +9.329928e-01, +9.307670e-01, +9.285061e-01, +9.262102e-01, + +9.238795e-01, +9.215140e-01, +9.191139e-01, +9.166791e-01, + +9.142098e-01, +9.117060e-01, +9.091680e-01, +9.065957e-01, + +9.039893e-01, +9.013488e-01, +8.986745e-01, +8.959662e-01, + +8.932243e-01, +8.904487e-01, +8.876396e-01, +8.847971e-01, + +8.819213e-01, +8.790122e-01, +8.760701e-01, +8.730950e-01, + +8.700870e-01, +8.670462e-01, +8.639729e-01, +8.608669e-01, + +8.577286e-01, +8.545580e-01, +8.513552e-01, +8.481203e-01, + +8.448536e-01, +8.415550e-01, +8.382247e-01, +8.348629e-01, + +8.314696e-01, +8.280450e-01, +8.245893e-01, +8.211025e-01, + +8.175848e-01, +8.140363e-01, +8.104572e-01, +8.068476e-01, + +8.032075e-01, +7.995373e-01, +7.958369e-01, +7.921066e-01, + +7.883464e-01, +7.845566e-01, +7.807372e-01, +7.768885e-01, + +7.730105e-01, +7.691033e-01, +7.651673e-01, +7.612024e-01, + +7.572088e-01, +7.531868e-01, +7.491364e-01, +7.450578e-01, + +7.409511e-01, +7.368166e-01, +7.326543e-01, +7.284644e-01, + +7.242471e-01, +7.200025e-01, +7.157308e-01, +7.114322e-01, + +7.071068e-01, +7.027547e-01, +6.983762e-01, +6.939715e-01, + +6.895405e-01, +6.850837e-01, +6.806010e-01, +6.760927e-01, + +6.715590e-01, +6.669999e-01, +6.624158e-01, +6.578067e-01, + +6.531728e-01, +6.485144e-01, +6.438315e-01, +6.391244e-01, + +6.343933e-01, +6.296382e-01, +6.248595e-01, +6.200572e-01, + +6.152316e-01, +6.103828e-01, +6.055110e-01, +6.006165e-01, + +5.956993e-01, +5.907597e-01, +5.857979e-01, +5.808140e-01, + +5.758082e-01, +5.707807e-01, +5.657318e-01, +5.606616e-01, + +5.555702e-01, +5.504580e-01, +5.453250e-01, +5.401715e-01, + +5.349976e-01, +5.298036e-01, +5.245897e-01, +5.193560e-01, + +5.141027e-01, +5.088301e-01, +5.035384e-01, +4.982277e-01, + +4.928982e-01, +4.875502e-01, +4.821838e-01, +4.767992e-01, + +4.713967e-01, +4.659765e-01, +4.605387e-01, +4.550836e-01, + +4.496113e-01, +4.441221e-01, +4.386162e-01, +4.330938e-01, + +4.275551e-01, +4.220003e-01, +4.164296e-01, +4.108432e-01, + +4.052413e-01, +3.996242e-01, +3.939920e-01, +3.883450e-01, + +3.826834e-01, +3.770074e-01, +3.713172e-01, +3.656130e-01, + +3.598950e-01, +3.541635e-01, +3.484187e-01, +3.426607e-01, + +3.368899e-01, +3.311063e-01, +3.253103e-01, +3.195020e-01, + +3.136817e-01, +3.078496e-01, +3.020059e-01, +2.961509e-01, + +2.902847e-01, +2.844075e-01, +2.785197e-01, +2.726214e-01, + +2.667128e-01, +2.607941e-01, +2.548657e-01, +2.489276e-01, + +2.429802e-01, +2.370236e-01, +2.310581e-01, +2.250839e-01, + +2.191012e-01, +2.131103e-01, +2.071114e-01, +2.011046e-01, + +1.950903e-01, +1.890687e-01, +1.830399e-01, +1.770042e-01, + +1.709619e-01, +1.649131e-01, +1.588581e-01, +1.527972e-01, + +1.467305e-01, +1.406582e-01, +1.345807e-01, +1.284981e-01, + +1.224107e-01, +1.163186e-01, +1.102222e-01, +1.041216e-01, + +9.801714e-02, +9.190896e-02, +8.579731e-02, +7.968244e-02, + +7.356456e-02, +6.744392e-02, +6.132074e-02, +5.519524e-02, + +4.906767e-02, +4.293826e-02, +3.680722e-02, +3.067480e-02, + +2.454123e-02, +1.840673e-02, +1.227154e-02, +6.135885e-03, + +6.123234e-17, -6.135885e-03, -1.227154e-02, -1.840673e-02, + -2.454123e-02, -3.067480e-02, -3.680722e-02, -4.293826e-02, + -4.906767e-02, -5.519524e-02, -6.132074e-02, -6.744392e-02, + -7.356456e-02, -7.968244e-02, -8.579731e-02, -9.190896e-02, + -9.801714e-02, -1.041216e-01, -1.102222e-01, -1.163186e-01, + -1.224107e-01, -1.284981e-01, -1.345807e-01, -1.406582e-01, + -1.467305e-01, -1.527972e-01, -1.588581e-01, -1.649131e-01, + -1.709619e-01, -1.770042e-01, -1.830399e-01, -1.890687e-01, + -1.950903e-01, -2.011046e-01, -2.071114e-01, -2.131103e-01, + -2.191012e-01, -2.250839e-01, -2.310581e-01, -2.370236e-01, + -2.429802e-01, -2.489276e-01, -2.548657e-01, -2.607941e-01, + -2.667128e-01, -2.726214e-01, -2.785197e-01, -2.844075e-01, + -2.902847e-01, -2.961509e-01, -3.020059e-01, -3.078496e-01, + -3.136817e-01, -3.195020e-01, -3.253103e-01, -3.311063e-01, + -3.368899e-01, -3.426607e-01, -3.484187e-01, -3.541635e-01, + -3.598950e-01, -3.656130e-01, -3.713172e-01, -3.770074e-01, + -3.826834e-01, -3.883450e-01, -3.939920e-01, -3.996242e-01, + -4.052413e-01, -4.108432e-01, -4.164296e-01, -4.220003e-01, + -4.275551e-01, -4.330938e-01, -4.386162e-01, -4.441221e-01, + -4.496113e-01, -4.550836e-01, -4.605387e-01, -4.659765e-01, + -4.713967e-01, -4.767992e-01, -4.821838e-01, -4.875502e-01, + -4.928982e-01, -4.982277e-01, -5.035384e-01, -5.088301e-01, + -5.141027e-01, -5.193560e-01, -5.245897e-01, -5.298036e-01, + -5.349976e-01, -5.401715e-01, -5.453250e-01, -5.504580e-01, + -5.555702e-01, -5.606616e-01, -5.657318e-01, -5.707807e-01, + -5.758082e-01, -5.808140e-01, -5.857979e-01, -5.907597e-01, + -5.956993e-01, -6.006165e-01, -6.055110e-01, -6.103828e-01, + -6.152316e-01, -6.200572e-01, -6.248595e-01, -6.296382e-01, + -6.343933e-01, -6.391244e-01, -6.438315e-01, -6.485144e-01, + -6.531728e-01, -6.578067e-01, -6.624158e-01, -6.669999e-01, + -6.715590e-01, -6.760927e-01, -6.806010e-01, -6.850837e-01, + -6.895405e-01, -6.939715e-01, -6.983762e-01, -7.027547e-01, + -7.071068e-01, -7.114322e-01, -7.157308e-01, -7.200025e-01, + -7.242471e-01, -7.284644e-01, -7.326543e-01, -7.368166e-01, + -7.409511e-01, -7.450578e-01, -7.491364e-01, -7.531868e-01, + -7.572088e-01, -7.612024e-01, -7.651673e-01, -7.691033e-01, + -7.730105e-01, -7.768885e-01, -7.807372e-01, -7.845566e-01, + -7.883464e-01, -7.921066e-01, -7.958369e-01, -7.995373e-01, + -8.032075e-01, -8.068476e-01, -8.104572e-01, -8.140363e-01, + -8.175848e-01, -8.211025e-01, -8.245893e-01, -8.280450e-01, + -8.314696e-01, -8.348629e-01, -8.382247e-01, -8.415550e-01, + -8.448536e-01, -8.481203e-01, -8.513552e-01, -8.545580e-01, + -8.577286e-01, -8.608669e-01, -8.639729e-01, -8.670462e-01, + -8.700870e-01, -8.730950e-01, -8.760701e-01, -8.790122e-01, + -8.819213e-01, -8.847971e-01, -8.876396e-01, -8.904487e-01, + -8.932243e-01, -8.959662e-01, -8.986745e-01, -9.013488e-01, + -9.039893e-01, -9.065957e-01, -9.091680e-01, -9.117060e-01, + -9.142098e-01, -9.166791e-01, -9.191139e-01, -9.215140e-01, + -9.238795e-01, -9.262102e-01, -9.285061e-01, -9.307670e-01, + -9.329928e-01, -9.351835e-01, -9.373390e-01, -9.394592e-01, + -9.415441e-01, -9.435935e-01, -9.456073e-01, -9.475856e-01, + -9.495282e-01, -9.514350e-01, -9.533060e-01, -9.551412e-01, + -9.569403e-01, -9.587035e-01, -9.604305e-01, -9.621214e-01, + -9.637761e-01, -9.653944e-01, -9.669765e-01, -9.685221e-01, + -9.700313e-01, -9.715039e-01, -9.729400e-01, -9.743394e-01, + -9.757021e-01, -9.770281e-01, -9.783174e-01, -9.795698e-01, + -9.807853e-01, -9.819639e-01, -9.831055e-01, -9.842101e-01, + -9.852776e-01, -9.863081e-01, -9.873014e-01, -9.882576e-01, + -9.891765e-01, -9.900582e-01, -9.909026e-01, -9.917098e-01, + -9.924795e-01, -9.932119e-01, -9.939070e-01, -9.945646e-01, + -9.951847e-01, -9.957674e-01, -9.963126e-01, -9.968203e-01, + -9.972905e-01, -9.977231e-01, -9.981181e-01, -9.984756e-01, + -9.987955e-01, -9.990777e-01, -9.993224e-01, -9.995294e-01, + -9.996988e-01, -9.998306e-01, -9.999247e-01, -9.999812e-01, + -1.000000e+00, -9.999812e-01, -9.999247e-01, -9.998306e-01, + -9.996988e-01, -9.995294e-01, -9.993224e-01, -9.990777e-01, + -9.987955e-01, -9.984756e-01, -9.981181e-01, -9.977231e-01, + -9.972905e-01, -9.968203e-01, -9.963126e-01, -9.957674e-01, + -9.951847e-01, -9.945646e-01, -9.939070e-01, -9.932119e-01, + -9.924795e-01, -9.917098e-01, -9.909026e-01, -9.900582e-01, + -9.891765e-01, -9.882576e-01, -9.873014e-01, -9.863081e-01, + -9.852776e-01, -9.842101e-01, -9.831055e-01, -9.819639e-01, + -9.807853e-01, -9.795698e-01, -9.783174e-01, -9.770281e-01, + -9.757021e-01, -9.743394e-01, -9.729400e-01, -9.715039e-01, + -9.700313e-01, -9.685221e-01, -9.669765e-01, -9.653944e-01, + -9.637761e-01, -9.621214e-01, -9.604305e-01, -9.587035e-01, + -9.569403e-01, -9.551412e-01, -9.533060e-01, -9.514350e-01, + -9.495282e-01, -9.475856e-01, -9.456073e-01, -9.435935e-01, + -9.415441e-01, -9.394592e-01, -9.373390e-01, -9.351835e-01, + -9.329928e-01, -9.307670e-01, -9.285061e-01, -9.262102e-01, + -9.238795e-01, -9.215140e-01, -9.191139e-01, -9.166791e-01, + -9.142098e-01, -9.117060e-01, -9.091680e-01, -9.065957e-01, + -9.039893e-01, -9.013488e-01, -8.986745e-01, -8.959662e-01, + -8.932243e-01, -8.904487e-01, -8.876396e-01, -8.847971e-01, + -8.819213e-01, -8.790122e-01, -8.760701e-01, -8.730950e-01, + -8.700870e-01, -8.670462e-01, -8.639729e-01, -8.608669e-01, + -8.577286e-01, -8.545580e-01, -8.513552e-01, -8.481203e-01, + -8.448536e-01, -8.415550e-01, -8.382247e-01, -8.348629e-01, + -8.314696e-01, -8.280450e-01, -8.245893e-01, -8.211025e-01, + -8.175848e-01, -8.140363e-01, -8.104572e-01, -8.068476e-01, + -8.032075e-01, -7.995373e-01, -7.958369e-01, -7.921066e-01, + -7.883464e-01, -7.845566e-01, -7.807372e-01, -7.768885e-01, + -7.730105e-01, -7.691033e-01, -7.651673e-01, -7.612024e-01, + -7.572088e-01, -7.531868e-01, -7.491364e-01, -7.450578e-01, + -7.409511e-01, -7.368166e-01, -7.326543e-01, -7.284644e-01, + -7.242471e-01, -7.200025e-01, -7.157308e-01, -7.114322e-01, + -7.071068e-01, -7.027547e-01, -6.983762e-01, -6.939715e-01, + -6.895405e-01, -6.850837e-01, -6.806010e-01, -6.760927e-01, + -6.715590e-01, -6.669999e-01, -6.624158e-01, -6.578067e-01, + -6.531728e-01, -6.485144e-01, -6.438315e-01, -6.391244e-01, + -6.343933e-01, -6.296382e-01, -6.248595e-01, -6.200572e-01, + -6.152316e-01, -6.103828e-01, -6.055110e-01, -6.006165e-01, + -5.956993e-01, -5.907597e-01, -5.857979e-01, -5.808140e-01, + -5.758082e-01, -5.707807e-01, -5.657318e-01, -5.606616e-01, + -5.555702e-01, -5.504580e-01, -5.453250e-01, -5.401715e-01, + -5.349976e-01, -5.298036e-01, -5.245897e-01, -5.193560e-01, + -5.141027e-01, -5.088301e-01, -5.035384e-01, -4.982277e-01, + -4.928982e-01, -4.875502e-01, -4.821838e-01, -4.767992e-01, + -4.713967e-01, -4.659765e-01, -4.605387e-01, -4.550836e-01, + -4.496113e-01, -4.441221e-01, -4.386162e-01, -4.330938e-01, + -4.275551e-01, -4.220003e-01, -4.164296e-01, -4.108432e-01, + -4.052413e-01, -3.996242e-01, -3.939920e-01, -3.883450e-01, + -3.826834e-01, -3.770074e-01, -3.713172e-01, -3.656130e-01, + -3.598950e-01, -3.541635e-01, -3.484187e-01, -3.426607e-01, + -3.368899e-01, -3.311063e-01, -3.253103e-01, -3.195020e-01, + -3.136817e-01, -3.078496e-01, -3.020059e-01, -2.961509e-01, + -2.902847e-01, -2.844075e-01, -2.785197e-01, -2.726214e-01, + -2.667128e-01, -2.607941e-01, -2.548657e-01, -2.489276e-01, + -2.429802e-01, -2.370236e-01, -2.310581e-01, -2.250839e-01, + -2.191012e-01, -2.131103e-01, -2.071114e-01, -2.011046e-01, + -1.950903e-01, -1.890687e-01, -1.830399e-01, -1.770042e-01, + -1.709619e-01, -1.649131e-01, -1.588581e-01, -1.527972e-01, + -1.467305e-01, -1.406582e-01, -1.345807e-01, -1.284981e-01, + -1.224107e-01, -1.163186e-01, -1.102222e-01, -1.041216e-01, + -9.801714e-02, -9.190896e-02, -8.579731e-02, -7.968244e-02, + -7.356456e-02, -6.744392e-02, -6.132074e-02, -5.519524e-02, + -4.906767e-02, -4.293826e-02, -3.680722e-02, -3.067480e-02, + -2.454123e-02, -1.840673e-02, -1.227154e-02, -6.135885e-03, + -1.836970e-16, +6.135885e-03, +1.227154e-02, +1.840673e-02, + +2.454123e-02, +3.067480e-02, +3.680722e-02, +4.293826e-02, + +4.906767e-02, +5.519524e-02, +6.132074e-02, +6.744392e-02, + +7.356456e-02, +7.968244e-02, +8.579731e-02, +9.190896e-02, + +9.801714e-02, +1.041216e-01, +1.102222e-01, +1.163186e-01, + +1.224107e-01, +1.284981e-01, +1.345807e-01, +1.406582e-01, + +1.467305e-01, +1.527972e-01, +1.588581e-01, +1.649131e-01, + +1.709619e-01, +1.770042e-01, +1.830399e-01, +1.890687e-01, + +1.950903e-01, +2.011046e-01, +2.071114e-01, +2.131103e-01, + +2.191012e-01, +2.250839e-01, +2.310581e-01, +2.370236e-01, + +2.429802e-01, +2.489276e-01, +2.548657e-01, +2.607941e-01, + +2.667128e-01, +2.726214e-01, +2.785197e-01, +2.844075e-01, + +2.902847e-01, +2.961509e-01, +3.020059e-01, +3.078496e-01, + +3.136817e-01, +3.195020e-01, +3.253103e-01, +3.311063e-01, + +3.368899e-01, +3.426607e-01, +3.484187e-01, +3.541635e-01, + +3.598950e-01, +3.656130e-01, +3.713172e-01, +3.770074e-01, + +3.826834e-01, +3.883450e-01, +3.939920e-01, +3.996242e-01, + +4.052413e-01, +4.108432e-01, +4.164296e-01, +4.220003e-01, + +4.275551e-01, +4.330938e-01, +4.386162e-01, +4.441221e-01, + +4.496113e-01, +4.550836e-01, +4.605387e-01, +4.659765e-01, + +4.713967e-01, +4.767992e-01, +4.821838e-01, +4.875502e-01, + +4.928982e-01, +4.982277e-01, +5.035384e-01, +5.088301e-01, + +5.141027e-01, +5.193560e-01, +5.245897e-01, +5.298036e-01, + +5.349976e-01, +5.401715e-01, +5.453250e-01, +5.504580e-01, + +5.555702e-01, +5.606616e-01, +5.657318e-01, +5.707807e-01, + +5.758082e-01, +5.808140e-01, +5.857979e-01, +5.907597e-01, + +5.956993e-01, +6.006165e-01, +6.055110e-01, +6.103828e-01, + +6.152316e-01, +6.200572e-01, +6.248595e-01, +6.296382e-01, + +6.343933e-01, +6.391244e-01, +6.438315e-01, +6.485144e-01, + +6.531728e-01, +6.578067e-01, +6.624158e-01, +6.669999e-01, + +6.715590e-01, +6.760927e-01, +6.806010e-01, +6.850837e-01, + +6.895405e-01, +6.939715e-01, +6.983762e-01, +7.027547e-01, + +7.071068e-01, +7.114322e-01, +7.157308e-01, +7.200025e-01, + +7.242471e-01, +7.284644e-01, +7.326543e-01, +7.368166e-01, + +7.409511e-01, +7.450578e-01, +7.491364e-01, +7.531868e-01, + +7.572088e-01, +7.612024e-01, +7.651673e-01, +7.691033e-01, + +7.730105e-01, +7.768885e-01, +7.807372e-01, +7.845566e-01, + +7.883464e-01, +7.921066e-01, +7.958369e-01, +7.995373e-01, + +8.032075e-01, +8.068476e-01, +8.104572e-01, +8.140363e-01, + +8.175848e-01, +8.211025e-01, +8.245893e-01, +8.280450e-01, + +8.314696e-01, +8.348629e-01, +8.382247e-01, +8.415550e-01, + +8.448536e-01, +8.481203e-01, +8.513552e-01, +8.545580e-01, + +8.577286e-01, +8.608669e-01, +8.639729e-01, +8.670462e-01, + +8.700870e-01, +8.730950e-01, +8.760701e-01, +8.790122e-01, + +8.819213e-01, +8.847971e-01, +8.876396e-01, +8.904487e-01, + +8.932243e-01, +8.959662e-01, +8.986745e-01, +9.013488e-01, + +9.039893e-01, +9.065957e-01, +9.091680e-01, +9.117060e-01, + +9.142098e-01, +9.166791e-01, +9.191139e-01, +9.215140e-01, + +9.238795e-01, +9.262102e-01, +9.285061e-01, +9.307670e-01, + +9.329928e-01, +9.351835e-01, +9.373390e-01, +9.394592e-01, + +9.415441e-01, +9.435935e-01, +9.456073e-01, +9.475856e-01, + +9.495282e-01, +9.514350e-01, +9.533060e-01, +9.551412e-01, + +9.569403e-01, +9.587035e-01, +9.604305e-01, +9.621214e-01, + +9.637761e-01, +9.653944e-01, +9.669765e-01, +9.685221e-01, + +9.700313e-01, +9.715039e-01, +9.729400e-01, +9.743394e-01, + +9.757021e-01, +9.770281e-01, +9.783174e-01, +9.795698e-01, + +9.807853e-01, +9.819639e-01, +9.831055e-01, +9.842101e-01, + +9.852776e-01, +9.863081e-01, +9.873014e-01, +9.882576e-01, + +9.891765e-01, +9.900582e-01, +9.909026e-01, +9.917098e-01, + +9.924795e-01, +9.932119e-01, +9.939070e-01, +9.945646e-01, + +9.951847e-01, +9.957674e-01, +9.963126e-01, +9.968203e-01, + +9.972905e-01, +9.977231e-01, +9.981181e-01, +9.984756e-01, + +9.987955e-01, +9.990777e-01, +9.993224e-01, +9.995294e-01, + +9.996988e-01, +9.998306e-01, +9.999247e-01, +9.999812e-01, }; -/* 1st local oscillator look-up table (subsampled cosine lut values) */ -static float i_lut[elems(cos_lut)], q_lut[elems(cos_lut)]; /* currently selected band */ static int curr_band; /* phase accumulator */ @@ -99,12 +289,16 @@ void OPTIMIZE("O3") Mix2_Mix(const float *i, const float *q, int num, float *i_out, float *q_out) { /* temporary storage */ - float _i, _q; + float _i, _q, i_lut, q_lut; + /* do the complex multiplication */ - for (int cnt = 0; cnt < num; cnt++, phase = (phase + 1) % elems(i_lut)) { + for (int cnt = 0; cnt < num; cnt++, phase = (phase + curr_band) % elems(cos_lut)) { + /* lut entries */ + i_lut = cos_lut[phase]; + q_lut = cos_lut[(phase + elems(cos_lut) / 4) % elems(cos_lut)]; /* (a + bi) * (c + di) = (ac - bd) + i(ad + bc) */ - _i = i[cnt] * i_lut[phase] - q[cnt] * q_lut[phase]; - _q = i[cnt] * q_lut[phase] + q[cnt] * i_lut[phase]; + _i = i[cnt] * i_lut - q[cnt] * q_lut; + _q = i[cnt] * q_lut + q[cnt] * i_lut; /* using temporary registers allows for in-situ operation */ i_out[cnt] = _i, q_out[cnt] = _q; } @@ -123,12 +317,6 @@ float Mix2_SetLOFrequency(float f) assert(band > -(int)elems(cos_lut) / 2 && band <= (int)elems(cos_lut) / 2, "unsupported band for mix2", band); - /* setup luts for in-phase and quadrature components. - * in-phase = cos(band * t), quadrature = -sin(band * t) */ - for (int i = 0; i < elems(cos_lut); i++) { - i_lut[i] = cos_lut[(i * band) & (elems(cos_lut) - 1)]; - q_lut[i] = cos_lut[((int)elems(cos_lut) / 4 + i * band) & (elems(cos_lut) - 1)]; - } /* store current band */ curr_band = band; /* return the actual frequency */ diff --git a/radio/src/radio.c b/radio/src/radio.c index 385a4e8..8468105 100644 --- a/radio/src/radio.c +++ b/radio/src/radio.c @@ -9,6 +9,7 @@ #include "assert.h" #include "err.h" +#include "at/ntf/radio.h" #include "dev/analog.h" #include "dev/await.h" #include "dev/cs43l22.h" @@ -118,7 +119,7 @@ static int Radio_JoystickCallback(void *ptr) if (ea->status & JOYSTICK_STATUS_LEFT) new_frequency -= frequency_change; /* sanity limits for the gain : +/- 40dB */ - new_gain = min(100, max(new_gain, 0.01)); + new_gain = min(1000, max(new_gain, 0.01)); /* sanity limits for the frequency: DC to Nyquist */ new_frequency = min(RF_SAMPLING_FREQ / 2, max(0, new_frequency)); @@ -179,8 +180,7 @@ static int Radio_AnalogCallback(void *ptr) { /* cast event argument */ analog_evarg_t *ea = ptr; - - /* head/tail adjusted pointers to the ping-pong buffer */ + /* head/tail adjusted pointers to the ping-pong buffer phase indicator */ float *i_dec_head = i_dec[ dec_pp], *q_dec_head = q_dec[ dec_pp]; float *i_dec_tail = i_dec[!dec_pp], *q_dec_tail = q_dec[!dec_pp]; /* number of samples after the hardware decimator */ @@ -209,11 +209,14 @@ static int Radio_AnalogCallback(void *ptr) Dec4_Decimate(i_dec_tail, q_dec_tail, hw_dec_num, i_dec_tail, q_dec_tail); + /* put the decimated data to the at notifications module */ + ATNtfRadio_PutIQSamples(i_dec_tail, q_dec_tail, sw_dec_num); + /* filter before demodulation */ - DemodAM_Filter(i_dec_tail, q_dec_tail, hw_dec_num / 4, i_dec_tail, + DemodAM_Filter(i_dec_tail, q_dec_tail, sw_dec_num, i_dec_tail, q_dec_tail); /* demodulate the output data */ - DemodAM_Demodulate(i_dec_tail, q_dec_tail, hw_dec_num / 4, dem); + DemodAM_Demodulate(i_dec_tail, q_dec_tail, sw_dec_num, dem); /* apply gain */ FloatScale_Scale(dem, sw_dec_num, set_gain, dem);