From 5e79b88354b006154b4a1a3e70b9bb44d40b0206 Mon Sep 17 00:00:00 2001 From: cnlohr Date: Tue, 4 Nov 2025 04:53:10 -0500 Subject: [PATCH] Add generic tools. They have not been validated yet. --- generic/Makefile | 8 + generic/genericgen.c | 361 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 369 insertions(+) create mode 100644 generic/Makefile create mode 100644 generic/genericgen.c diff --git a/generic/Makefile b/generic/Makefile new file mode 100644 index 0000000..024c8d4 --- /dev/null +++ b/generic/Makefile @@ -0,0 +1,8 @@ +all : genericgen + +genericgen : genericgen.c + gcc -g -o $@ $^ + +clean : + rm -rf genericgen + diff --git a/generic/genericgen.c b/generic/genericgen.c new file mode 100644 index 0000000..f44f112 --- /dev/null +++ b/generic/genericgen.c @@ -0,0 +1,361 @@ +/** + +MIT-like-non-ai-license + +Copyright (c) 2024 Charles Lohr "CNLohr" + +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 two following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +In addition the following restrictions apply: + +1. The Software and any modifications made to it may not be used for the +purpose of training or improving machine learning algorithms, including but not +limited to artificial intelligence, natural language processing, or data +mining. This condition applies to any derivatives, modifications, or updates +based on the Software code. Any usage of the Software in an AI-training dataset +is considered a breach of this License. + +2. The Software may not be included in any dataset used for training or +improving machine learning algorithms, including but not limited to artificial +intelligence, natural language processing, or data mining. + +3. Any person or organization found to be in violation of these restrictions +will be subject to legal action and may be held liable for any damages +resulting from such use. + +If any term is unenforcable, other terms remain in-force. + +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. + +**/ + +// Designed for generating chirp buffer to mimic hackaday badge... The idea is +// you can feed this data you want to send... and it feeds you a generic +// language of quarter chirps telling you when to up or down chirp. +// +// If the output value is negative, you need to emit a down-chirp. If it is +// positive, you output an up-chirp. +// +// Down chirps are represented in one's compliment. + + + + +#include +#include +#include + +#include "../lib/LoRa-SDR-Code.h" + +// Optionally send LoRaWAN messages. Be sure to copy your keys from the things network. +//#define LORAWAN +#define HACKADAY + + +#ifdef LORAWAN +#include "lorawan_simple.h" + static const uint8_t payload_key[AES_BLOCKLEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // AppSKey Big Endian + static const uint8_t network_skey[AES_BLOCKLEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // NwkSKey Big Endian + static const uint8_t devaddress[4] = { 0x00, 0x00, 0x00, 0x00 }; // Device address Little Endian LSB (Written backwards from Device address default view) +#endif + +#ifdef HACKADAY +#define SF_NUMBER 7 +#define CHIRPLENGTH_WORDS 128 +#endif + +#if !defined( LORAWAN ) && !defined( HACKADAY ) +#error Need to define LORWAN or HACKADAY +#endif + +// Bits are shifted out MSBit first, then to LSBit + + +#define MAX_BYTES 160 +#define MAX_SYMBOLS (MAX_BYTES*2+16) + +// Our table is bespoke for the specific SF. +#define CHIPSSPREAD CHIRPLENGTH_WORDS // QUARTER_CHIRP_LENGTH_WORDS (TODO: Use the quater value elsewhere in the code) +#define MARK_FROM_SF0 (1<CFGR0 &= ~RCC_PPRE1_DIV16; + +// MCO for testing. +// funPinMode( PA8, GPIO_CFGLR_OUT_50Mhz_AF_PP ); RCC->CFGR0 |= RCC_CFGR0_MCO_PLL; + + printf( "Switching to HSE\n" ); + Delay_Ms( 100 ); + + // Disable clock security system. + RCC->CTLR &= ~RCC_CSSON; + +#ifdef USE_EXTERNAL_CLOCK + // No crystal - use clock. + RCC->CTLR |= RCC_HSEBYP; +#endif + + // Enable external crystal + RCC->CTLR |= RCC_HSEON; + + // Set System Clock Source to be 0. + RCC->CFGR0 = (RCC->CFGR0 & ~RCC_SW) | 0; + + // Disable PLL + RCC->CTLR &= ~RCC_PLLON; + + +#ifdef USE_EXTERNAL_CLOCK + // Set PLL to 9x not 18x + RCC->CFGR0 = ( RCC->CFGR0 & ~RCC_PLLMULL18 ) | RCC_PLLMULL9; +#endif + + // Switch to HSE + RCC->CFGR0 |= RCC_PLLSRC; + + // Enable PLL + RCC->CTLR |= RCC_PLLON; + + // Wait for HSE to become ready. + while( !( RCC->CTLR & RCC_HSERDY) ); + while( !( RCC->CTLR & RCC_PLLRDY) ); + RCC->CFGR0 |= RCC_SW_1; // Switch system clock to PLL + printf( "HSE Switched\n" ); + Delay_Ms( 10 ); + RCC->CTLR &= ~RCC_HSION; + Delay_Ms( 10 ); + printf( "HSI Off [%08lx %08lx]\n", RCC->CTLR, RCC->CFGR0 ); + +// funPinMode( PB12, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // NSS +// funPinMode( PB13, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // SCK +// funPinMode( PB14, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // MISO + funPinMode( PB15, GPIO_CFGLR_OUT_50Mhz_AF_PP ); // MOSI + + RCC->APB1PRSTR = RCC_SPI2RST; + RCC->APB1PRSTR = 0; + RCC->APB1PCENR |= RCC_APB1Periph_SPI2; + RCC->AHBPCENR |= RCC_AHBPeriph_DMA1; + + // Configure SPI + SPI2->CTLR1 = + SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b | + SPI_Mode_Master | SPI_Direction_1Line_Tx | + 0 | + 0<<3; // Divisior = 0 + + // If using DMA may need this. + SPI2->CTLR2 = SPI_CTLR2_TXDMAEN; + + + SPI2->HSCR = 1; // High-speed enable. + + SPI2->CTLR1 |= CTLR1_SPE_Set; + //SPI2->DATAR = 0x55aa; // Set SPI line Low. + + //DMA1_Channel5 is for SPI2TX + DMA1_Channel5->PADDR = (uint32_t)&SPI2->DATAR; + DMA1_Channel5->MADDR = (uint32_t)sendbuff; + DMA1_Channel5->CNTR = 0;// sizeof( bufferset )/2; // Number of unique copies. (Don't start, yet!) + DMA1_Channel5->CFGR = + DMA_M2M_Disable | + DMA_Priority_VeryHigh | + DMA_MemoryDataSize_HalfWord | + DMA_PeripheralDataSize_HalfWord | + DMA_MemoryInc_Enable | + DMA_Mode_Normal | // OR DMA_Mode_Circular or DMA_Mode_Normal + DMA_DIR_PeripheralDST | + DMA_IT_TC | DMA_IT_HT; // Transmission Complete + Half Empty Interrupts. + + NVIC_EnableIRQ( DMA1_Channel5_IRQn ); + DMA1_Channel5->CFGR |= DMA_CFGR1_EN; + + + memset( sendbuff, 0x00, sizeof( sendbuff ) ); + + // Enter critical section. + DMA1_Channel5->CNTR = 0; + DMA1_Channel5->MADDR = (uint32_t)sendbuff; + DMA1_Channel5->CNTR = SENDBUFF_WORDS; // Number of unique uint16_t entries. + DMA1_Channel5->CFGR |= DMA_Mode_Circular; +#endif + + uint16_t lora_symbols[MAX_SYMBOLS]; + int lora_symbols_count; + + //while(1) + { + + //Delay_Ms( 1000 ); + + +#ifdef LORAWAN + //Delay_Ms( 1000 ); + static uint32_t frame = 0; + + // Send a message with LoraWan. Formatted specifically for thethings.network. + uint8_t inner_payload_raw[24]; + int inner_payload_len = snprintf( (char*)inner_payload_raw, 24, "meow%lu ", frame%10 ); + inner_payload_len = 5; + + // Just some random data. + uint8_t raw_payload_with_b0[259+8] = { }; + uint8_t * payload_in = raw_payload_with_b0 + 16; + uint8_t * pl = payload_in; + int payload_in_size = 0; + + pl += GenerateLoRaWANPacket( raw_payload_with_b0, inner_payload_raw, inner_payload_len, payload_key, network_skey, devaddress, frame++); + + payload_in_size = pl - payload_in; + + lora_symbols_count = 0; +#else + + // Just some random data. + + uint8_t payload_in[128] = { + 0x07, 0xe9, 0x23, 0xee, 0x03, 0x80, 0xff, 0xff, 0xff, 0xff, 0x16, 0xca, + 0x51, 0xd0, 0x06, 0x00, 0x02, 0x59, 0x6c, 0x6f, 0x6c, 0x72, 0x61, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x61, 0x61, 0x61, 0x61, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + int payload_in_size = sizeof(payload_in); + + static int msgno = 0; + payload_in[4] = msgno++; + + +#endif + + lora_symbols_count = 0; +// int r = CreateMessageFromPayload( lora_symbols, &lora_symbols_count, MAX_SYMBOLS, SF_NUMBER, 4, payload_in, payload_in_size ); + + // I think the Hackaday swadge uses 5/4, not 8/4 + int r = CreateMessageFromPayload( lora_symbols, &lora_symbols_count, MAX_SYMBOLS, SF_NUMBER, 1, payload_in, payload_in_size ); + + if( r < 0 ) + { + printf( "Failed to generate message (%d)\n", r ); + // Failed + return -1; + } + + int j; + + quadsetcount = 0; + int16_t * qso = quadsets; + for( j = 0; j < PREAMBLE_CHIRPS; j++ ) + { + qso = AddChirp( qso, 0, 0 ); + } + + // Hackaday Syncword. + uint8_t syncword = 0x21; + + #define CODEWORD_SHIFT 3 + + if( CODEWORD_LENGTH > 0 ) + qso = AddChirp( qso, ( ( syncword & 0xf ) << CODEWORD_SHIFT ), 0 ); + if( CODEWORD_LENGTH > 1 ) + qso = AddChirp( qso, ( ( ( syncword & 0xf0 ) >> 4 ) << CODEWORD_SHIFT ), 0); + + *(qso++) = -(CHIPSSPREAD * 0 / 4 )-1; + *(qso++) = -(CHIPSSPREAD * 1 / 4 )-1; + *(qso++) = -(CHIPSSPREAD * 2 / 4 )-1; + *(qso++) = -(CHIPSSPREAD * 3 / 4 )-1; + *(qso++) = -(CHIPSSPREAD * 0 / 4 )-1; + *(qso++) = -(CHIPSSPREAD * 1 / 4 )-1; + *(qso++) = -(CHIPSSPREAD * 2 / 4 )-1; + *(qso++) = -(CHIPSSPREAD * 3 / 4 )-1; + *(qso++) = -(CHIPSSPREAD * 0 / 4 )-1; + + if( SF_NUMBER <= 6 ) + { + // Two additional upchirps with SF6 https://github.com/tapparelj/gr-lora_sdr/issues/74#issuecomment-1891569580 + for( j = 0; j < 2; j++ ) + qso = AddChirp( qso, 0, 0 ); + } + + for( j = 0; j < lora_symbols_count; j++ ) + { + int ofs = lora_symbols[j]; + //ofs = ofs ^ ((MARK_FROM_SF6<<6) -1); + //ofs &= (MARK_FROM_SF6<<6) -1; + qso = AddChirp( qso, ofs, 0 ); + //printf( "0x%03x, ", ofs ); + } + printf( "\n" ); + + printf( "const int16_t quadstarts[%ld] = {", qso - quadsets ); + for (j = 0; j < qso - quadsets; j++ ) + { + if( ( j & 0xf ) == 0 ) printf( "\n\t" ); + printf( "%4d, ", quadsets[j] ); + } + printf( "};\n" ); +//int16_t * qso = quadsets + + + runningcount_bits = 0; + + // This tells the interrupt we have data. + quadsetcount = qso - quadsets + 0; + printf( "--- %d [%d] %d\n", (int)lora_symbols_count, (int)quadsetcount, CHIPSSPREAD/4 ); + + quadsetplace = 0; + + } +} +