mirror of
https://github.com/cnlohr/lolra.git
synced 2026-06-17 00:09:31 +00:00
Initial Commit
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
MIT 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 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.
|
||||
*/
|
||||
|
||||
#ifndef _ESP8266_I2S_SETUP
|
||||
#define _ESP8266_I2S_SETUP
|
||||
|
||||
#include "slc_register.h"
|
||||
#include "dmastuff.h"
|
||||
|
||||
/* Need something like:
|
||||
|
||||
#define DMABUFFERDEPTH 3
|
||||
#define WS_I2S_BCK SPI_DIV //Can't be less than 1.
|
||||
#define WS_I2S_DIV 1
|
||||
|
||||
*/
|
||||
|
||||
static struct sdio_queue i2sBufDescTX[DMABUFFERDEPTH] __attribute__((aligned(128)));;
|
||||
|
||||
void slc_isr(void * v);
|
||||
|
||||
static void testi2s_init( uint32_t * initial_data );
|
||||
|
||||
//Initialize I2S subsystem for DMA circular buffer use
|
||||
static void testi2s_init( uint32_t * default_data ) {
|
||||
int x, y;
|
||||
//Bits are shifted out
|
||||
|
||||
//Initialize DMA buffer descriptors in such a way that they will form a circular
|
||||
//buffer.
|
||||
|
||||
for (x=0; x<DMABUFFERDEPTH; x++) {
|
||||
i2sBufDescTX[x].owner=1;
|
||||
i2sBufDescTX[x].eof=1; // Trigger interrupt on packet complete.
|
||||
i2sBufDescTX[x].sub_sof=0;
|
||||
i2sBufDescTX[x].datalen=DMA_SIZE_WORDS*4;
|
||||
i2sBufDescTX[x].blocksize=4;
|
||||
i2sBufDescTX[x].buf_ptr= ((uint32_t)default_data);
|
||||
i2sBufDescTX[x].unused=0;
|
||||
i2sBufDescTX[x].next_link_ptr=(int)((x<(DMABUFFERDEPTH-1))?(&i2sBufDescTX[x+1]):(&i2sBufDescTX[0]));
|
||||
}
|
||||
|
||||
//Reset DMA )
|
||||
//SLC_TX_LOOP_TEST = IF this isn't set, SO will occasionally get unrecoverable errors when you underflow.
|
||||
//Originally this little tidbit was found at https://github.com/pvvx/esp8266web/blob/master/info/libs/bios/sip_slc.c
|
||||
//
|
||||
//I have not tried without SLC_AHBM_RST | SLC_AHBM_FIFO_RST. I just assume they are useful?
|
||||
SET_PERI_REG_MASK(SLC_CONF0, SLC_TX_LOOP_TEST |SLC_RXLINK_RST|SLC_TXLINK_RST|SLC_AHBM_RST | SLC_AHBM_FIFO_RST);
|
||||
CLEAR_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST|SLC_TXLINK_RST|SLC_AHBM_RST | SLC_AHBM_FIFO_RST);
|
||||
|
||||
//Clear DMA int flags
|
||||
SET_PERI_REG_MASK(SLC_INT_CLR, 0xffffffff);
|
||||
CLEAR_PERI_REG_MASK(SLC_INT_CLR, 0xffffffff);
|
||||
|
||||
//Enable and configure DMA
|
||||
CLEAR_PERI_REG_MASK(SLC_CONF0, (SLC_MODE<<SLC_MODE_S));
|
||||
SET_PERI_REG_MASK(SLC_CONF0,(1<<SLC_MODE_S));
|
||||
|
||||
// We have to do this, otherwise, when the end of a "RX" packet is hit, it will skip outputting a few random frames.
|
||||
SET_PERI_REG_MASK(SLC_RX_DSCR_CONF,SLC_INFOR_NO_REPLACE|SLC_TOKEN_NO_REPLACE);
|
||||
CLEAR_PERI_REG_MASK(SLC_RX_DSCR_CONF, SLC_RX_FILL_EN|SLC_RX_EOF_MODE | SLC_RX_FILL_MODE);
|
||||
|
||||
CLEAR_PERI_REG_MASK(SLC_RX_LINK,SLC_RXLINK_DESCADDR_MASK);
|
||||
SET_PERI_REG_MASK(SLC_RX_LINK, ((uint32)&i2sBufDescTX[0]) & SLC_RXLINK_DESCADDR_MASK);
|
||||
|
||||
//Attach the DMA interrupt
|
||||
ets_isr_attach(ETS_SLC_INUM, slc_isr, 0);
|
||||
WRITE_PERI_REG(SLC_INT_ENA, SLC_RX_EOF_INT_ENA ); // Not including SLC_RX_UDF_INT_ENA
|
||||
|
||||
//clear any interrupt flags that are set
|
||||
WRITE_PERI_REG(SLC_INT_CLR, 0xffffffff);
|
||||
///enable DMA intr in cpu
|
||||
ets_isr_unmask(1<<ETS_SLC_INUM);
|
||||
|
||||
//Start transmission
|
||||
SET_PERI_REG_MASK(SLC_RX_LINK, SLC_RXLINK_START);
|
||||
|
||||
|
||||
//Init pins to i2s functions
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_I2SO_DATA); // GPIO3
|
||||
// PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_I2SO_WS); // GPIO2
|
||||
// PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_I2SO_BCK); // GPIO15
|
||||
|
||||
//Enable clock to i2s subsystem
|
||||
i2c_writeReg_Mask_def(i2c_bbpll, i2c_bbpll_en_audio_clock_out, 1);
|
||||
|
||||
//Reset I2S subsystem
|
||||
CLEAR_PERI_REG_MASK(I2SCONF,I2S_I2S_RESET_MASK);
|
||||
SET_PERI_REG_MASK(I2SCONF,I2S_I2S_RESET_MASK);
|
||||
CLEAR_PERI_REG_MASK(I2SCONF,I2S_I2S_RESET_MASK);
|
||||
|
||||
CLEAR_PERI_REG_MASK(I2S_FIFO_CONF, I2S_I2S_DSCR_EN|(I2S_I2S_RX_FIFO_MOD<<I2S_I2S_RX_FIFO_MOD_S));
|
||||
SET_PERI_REG_MASK(I2S_FIFO_CONF, I2S_I2S_DSCR_EN);
|
||||
WRITE_PERI_REG(I2SRXEOF_NUM, DMA_SIZE_WORDS*4);
|
||||
|
||||
CLEAR_PERI_REG_MASK(I2SCONF_CHAN, (I2S_RX_CHAN_MOD<<I2S_RX_CHAN_MOD_S));
|
||||
|
||||
CLEAR_PERI_REG_MASK(I2SCONF, I2S_TRANS_SLAVE_MOD|I2S_RECE_SLAVE_MOD|
|
||||
(I2S_BITS_MOD<<I2S_BITS_MOD_S)|
|
||||
(I2S_BCK_DIV_NUM <<I2S_BCK_DIV_NUM_S)|
|
||||
(I2S_CLKM_DIV_NUM<<I2S_CLKM_DIV_NUM_S));
|
||||
|
||||
SET_PERI_REG_MASK(I2SCONF, I2S_RIGHT_FIRST|I2S_MSB_RIGHT|
|
||||
I2S_RECE_MSB_SHIFT|I2S_TRANS_MSB_SHIFT|
|
||||
((WS_I2S_BCK&I2S_BCK_DIV_NUM )<<I2S_BCK_DIV_NUM_S)|
|
||||
((WS_I2S_DIV&I2S_CLKM_DIV_NUM)<<I2S_CLKM_DIV_NUM_S) );
|
||||
|
||||
//Start transmission
|
||||
SET_PERI_REG_MASK(I2SCONF,I2S_I2S_TX_START|I2S_I2S_RX_START);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
all : chirpbuff.dat.flash
|
||||
|
||||
SUBMODULE=YES
|
||||
SRCPREFIX=../nosdk8266/
|
||||
MAIN_MHZ=52
|
||||
SRCS=main.c
|
||||
DEPS=chirpbuffinfo.h
|
||||
COMPILECOUNT=$(shell cat compilecount.txt || true)
|
||||
BUILDCOUNTCMD=echo 1+0$(COMPILECOUNT) | bc > compilecount.txt | true Compiled $(COMPILECOUNT) times
|
||||
CFLAGS=-I../../lib -I..
|
||||
|
||||
include ../nosdk8266/Makefile
|
||||
|
||||
rf_data_gen : rf_data_gen.c
|
||||
gcc -o $@ $^ -lm -DMAIN_MHZ=$(MAIN_MHZ)
|
||||
|
||||
chirpbuffinfo.h : chirpbuff.dat
|
||||
|
||||
teststrap : main.c chirpbuff.dat
|
||||
gcc -o teststrap main.c -DTESTSTRAP -I../nosdk8266/include
|
||||
|
||||
|
||||
chirpbuff.dat : rf_data_gen
|
||||
./rf_data_gen
|
||||
|
||||
chirpbuff.dat.flash : chirpbuff.dat
|
||||
$(ESPUTIL) -b 115200 flash 0x20000 chirpbuff.dat
|
||||
|
||||
cleanall : clean
|
||||
rm -rf chirpbuff.h rf_data_gen chirpbuff.dat chirpbuffinfo.h
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# ESP8266 / ESP8285 Lora Transmitter
|
||||
|
||||
Connect a small length of wire to the "RX" pin on your ESP8266, then it will transmit SF7 LoRa messages at 904.1MHz.
|
||||
|
||||
This is designed to work at 173MHz, but, you can set `MAIN_MHZ=80` in the Makefile, and run it without any overclocking.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
45
|
||||
@@ -0,0 +1,378 @@
|
||||
/**
|
||||
|
||||
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.
|
||||
|
||||
**/
|
||||
|
||||
// This was my first test, it still contains a number of TESTSTRAP flags.
|
||||
// Teststrap was used when I compiled and ran this code on a host PC.
|
||||
// In general, don't use this, code is just left around in case I run into
|
||||
// any really weird bugs.
|
||||
#ifdef TESTSTRAP
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "chirpbuff.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define uint32 uint32_t
|
||||
|
||||
#else
|
||||
|
||||
#include "esp8266_auxrom.h"
|
||||
#include "eagle_soc.h"
|
||||
#include "nosdk8266.h"
|
||||
#include "esp8266_rom.h"
|
||||
|
||||
// TODO: Use float number (related to 8) to fix the drift
|
||||
#define call_delay_us(time) { asm volatile("mov.n a2, %0\n_call0 delay4clk" : : "r"(time * (MAIN_MHZ / 8)) : "a2" ); }
|
||||
|
||||
#include "ets_sys.h"
|
||||
#include "pin_mux_register.h"
|
||||
|
||||
#endif
|
||||
|
||||
#include "slc_register.h"
|
||||
#include "dmastuff.h"
|
||||
#include "chirpbuffinfo.h"
|
||||
#include "LoRa-SDR-Code.h"
|
||||
|
||||
#define DMABUFFERDEPTH 3
|
||||
//These contol the speed at which the bus comms.
|
||||
#define WS_I2S_BCK SPI_DIV //Can't be less than 1.
|
||||
#define WS_I2S_DIV 1
|
||||
|
||||
#ifndef TESTSTRAP
|
||||
#include "esp8266_i2s_setup.h"
|
||||
#endif
|
||||
|
||||
uint32_t chirpbuffUP[CHIRPLENGTH_WORDS_WITH_PADDING];
|
||||
uint32_t chirpbuffDOWN[CHIRPLENGTH_WORDS_WITH_PADDING];
|
||||
uint32_t dummy[DMA_SIZE_WORDS];
|
||||
|
||||
volatile int fxcycle;
|
||||
int etx;
|
||||
|
||||
// Limit because of RAM usage, but this should be able to hold a practical limit of a 255 byte LoRa packet.
|
||||
#define MAX_SYMBOLS 532
|
||||
|
||||
|
||||
// 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<<SF_NUMBER) // SF7
|
||||
|
||||
#define PREAMBLE_CHIRPS 10
|
||||
#define CODEWORD_LENGTH 2
|
||||
|
||||
uint32_t quadsetcount;
|
||||
int32_t quadsets[MAX_SYMBOLS*4+PREAMBLE_CHIRPS*4+9+CODEWORD_LENGTH*4];
|
||||
|
||||
int32_t * AddChirp( int32_t * qso, int offset, int verneer )
|
||||
{
|
||||
offset = offset * CHIPSSPREAD / (MARK_FROM_SF0);
|
||||
offset += verneer;
|
||||
*(qso++) = (CHIPSSPREAD * 0 / 4 + offset + CHIPSSPREAD ) % CHIPSSPREAD;
|
||||
*(qso++) = (CHIPSSPREAD * 1 / 4 + offset + CHIPSSPREAD ) % CHIPSSPREAD;
|
||||
*(qso++) = (CHIPSSPREAD * 2 / 4 + offset + CHIPSSPREAD ) % CHIPSSPREAD;
|
||||
*(qso++) = (CHIPSSPREAD * 3 / 4 + offset + CHIPSSPREAD ) % CHIPSSPREAD;
|
||||
return qso;
|
||||
}
|
||||
|
||||
|
||||
volatile int quadsetplace = -1;
|
||||
|
||||
int runningcount_bits = 0;
|
||||
|
||||
void slc_isr(void * v) {
|
||||
|
||||
uint32_t * sendbuff = 0;
|
||||
uint32_t sendlen = 0;
|
||||
struct sdio_queue *finishedDesc;
|
||||
// slc_intr_status = READ_PERI_REG(SLC_INT_STATUS); -> We should check to make sure we are SLC_RX_EOF_INT_ST, but we are only getting one interrupt.
|
||||
#ifdef TESTSTRAP
|
||||
struct sdio_queue tmp;
|
||||
finishedDesc = &tmp;
|
||||
#else
|
||||
WRITE_PERI_REG(SLC_INT_CLR, 0xffffffff);
|
||||
finishedDesc=(struct sdio_queue*)READ_PERI_REG(SLC_RX_EOF_DES_ADDR);
|
||||
#endif
|
||||
|
||||
etx++;
|
||||
|
||||
if( quadsetplace < 0 )
|
||||
{
|
||||
goto dump0;
|
||||
}
|
||||
|
||||
// LoRa symbols are in quarters of a chirp.
|
||||
if( fxcycle>= NUM_DMAS_PER_QUARTER_CHIRP )
|
||||
{
|
||||
fxcycle = 0;
|
||||
quadsetplace++;
|
||||
if( quadsetplace >= quadsetcount ) goto dump0;
|
||||
}
|
||||
|
||||
int symbol = quadsets[quadsetplace];
|
||||
|
||||
// Select down- or up-chirp.
|
||||
if( symbol < 0 )
|
||||
{
|
||||
int word = fxcycle * DMA_SIZE_WORDS - symbol - 1;
|
||||
if( word >= CHIPSSPREAD ) word -= CHIPSSPREAD;
|
||||
word++;
|
||||
sendbuff = (chirpbuffDOWN + word);
|
||||
}
|
||||
else
|
||||
{
|
||||
int word = fxcycle * DMA_SIZE_WORDS + symbol;
|
||||
if( word >= CHIPSSPREAD ) word -= CHIPSSPREAD;
|
||||
sendbuff = (chirpbuffUP + word);
|
||||
}
|
||||
|
||||
#ifndef FOUND_PERFECT_DIVISOR
|
||||
// Sometimes we do the full length, of all of the needed DMAs
|
||||
// Sometimes we overshoot the time window, so we peel off 4 bytes.
|
||||
//
|
||||
// Very few combinations of clock rate, divisor, etc can produce
|
||||
// perfect divisors. Most notably 52MHz, /2 SF9 can produce a perfect
|
||||
// divisor. While this is very tidy and beautiful that the
|
||||
// words would align perfectly, the actual difference it makes on
|
||||
// LoRa's ability to receive the message is minimal.
|
||||
//
|
||||
// Additionally, 80MHz /2 SF7 can produce a perfect divisor.
|
||||
int running_bits_after = runningcount_bits + DMA_SIZE_WORDS*32;
|
||||
int overflow = running_bits_after - IDEAL_QUARTER_CHIRP_LENGTH_BITS;
|
||||
if( overflow >= 0 )
|
||||
{
|
||||
int overflow_amount = overflow / 32;
|
||||
int overflow_remainder = overflow % 32;
|
||||
sendlen = DMA_SIZE_WORDS*4 - 4*overflow_amount;
|
||||
runningcount_bits = overflow_remainder;
|
||||
|
||||
// XXX TODO: Why can't I put the logic for advancing the group in here?
|
||||
}
|
||||
else
|
||||
{
|
||||
sendlen = DMA_SIZE_WORDS*4;
|
||||
runningcount_bits = running_bits_after;
|
||||
}
|
||||
#else
|
||||
sendlen = DMA_SIZE_WORDS*4;
|
||||
#endif
|
||||
|
||||
#ifdef TESTSTRAP
|
||||
static FILE * fappendlog;
|
||||
if( !fappendlog ) fappendlog = fopen( "fappendlog.csv", "w" );
|
||||
{
|
||||
if( symbol < 0 )
|
||||
fprintf( fappendlog, "2, %d, %d\n", (int)(CHIRPLENGTH_WORDS - (sendbuff - chirpbuffDOWN) - 1), sendlen );
|
||||
else
|
||||
fprintf( fappendlog, "1, %d, %d\n", (int)(sendbuff - chirpbuffUP), sendlen );
|
||||
}
|
||||
#else
|
||||
finishedDesc->buf_ptr = (uint32_t)sendbuff;
|
||||
finishedDesc->datalen = sendlen;
|
||||
#endif
|
||||
|
||||
fxcycle++;
|
||||
return;
|
||||
|
||||
|
||||
dump0:
|
||||
#ifdef TESTSTRAP
|
||||
printf( "Hit dummy %d %d\n", quadsetplace, quadsetcount );
|
||||
exit( 0 );
|
||||
#else
|
||||
// This location just always reads as zeroes.
|
||||
finishedDesc->buf_ptr = (uint32_t)dummy;
|
||||
quadsetplace = -1;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TESTSTRAP
|
||||
|
||||
void SPIRead( uint32_t pos, uint32_t * buff, int len )
|
||||
{
|
||||
memcpy( buff, (pos - 0x00020000) + (uint8_t*)chirpbuff, len );
|
||||
}
|
||||
|
||||
void nosdk8266_init()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void testi2s_init( uint32_t * default_address )
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
// We store the bit pattern at flash:0x20000, so we don't have to constantly
|
||||
// re-write it when working on code.
|
||||
SPIRead( MEMORY_START_OFFSET_BYTES, chirpbuffUP, sizeof( chirpbuffUP ) );
|
||||
SPIRead( REVERSE_START_OFFSET_BYTES, chirpbuffDOWN, sizeof( chirpbuffDOWN ) );
|
||||
memset( dummy, 0, sizeof( dummy ) );
|
||||
|
||||
// Don't crank up clock speed til we're done with flash.
|
||||
nosdk8266_init();
|
||||
|
||||
|
||||
int i = 0;
|
||||
fxcycle = 0;
|
||||
etx = 0;
|
||||
|
||||
|
||||
#ifndef TESTSTRAP
|
||||
// Configure GPIO5 (TX) and GPIO2 (LED)
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U,FUNC_GPIO2);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U,FUNC_GPIO5);
|
||||
PIN_DIR_OUTPUT = _BV(2); //Enable GPIO2 light off.
|
||||
|
||||
// Run the I2S bus at 1040/6 = 173.333 MHz.
|
||||
// It looks like, at least on my part, if I try running
|
||||
// hotter it can get to 1040/5.1 but not all the way to
|
||||
// 5 so it's unstable there.
|
||||
#endif
|
||||
testi2s_init( dummy );
|
||||
|
||||
int frame = 0;
|
||||
uint16_t lora_symbols[MAX_SYMBOLS];
|
||||
int lora_symbols_count;
|
||||
|
||||
while(1) {
|
||||
//12x this speed.
|
||||
frame++;
|
||||
#ifndef TESTSTRAP
|
||||
PIN_OUT_SET = _BV(2); //Turn GPIO2 light off.
|
||||
//call_delay_us(1000000);
|
||||
printf("ETX: %d %08x\n", fxcycle, chirpbuffUP[10] );
|
||||
PIN_OUT_CLEAR = _BV(2); //Turn GPIO2 light off.
|
||||
call_delay_us(500000);
|
||||
#endif
|
||||
call_delay_us(2000000);
|
||||
|
||||
// Just some random data.
|
||||
uint8_t payload_in[259] = { 0xbb, 0xcc, 0xde, 0x55, 0x22,};
|
||||
int payload_in_size = 6;
|
||||
|
||||
static int msgno = 0;
|
||||
payload_in[4] = msgno++;
|
||||
|
||||
lora_symbols_count = 0;
|
||||
int r = CreateMessageFromPayload( lora_symbols, &lora_symbols_count, MAX_SYMBOLS, SF_NUMBER, 4, payload_in, payload_in_size );
|
||||
|
||||
if( r < 0 )
|
||||
{
|
||||
printf( "Failed to generate message (%d)\n", r );
|
||||
// Failed
|
||||
continue;
|
||||
}
|
||||
|
||||
int j;
|
||||
|
||||
quadsetcount = 0;
|
||||
int32_t * qso = quadsets;
|
||||
for( j = 0; j < PREAMBLE_CHIRPS; j++ )
|
||||
{
|
||||
qso = AddChirp( qso, 0, 0 );
|
||||
}
|
||||
|
||||
uint8_t syncword = 0x43;
|
||||
|
||||
#if SF_NUMBER == 6
|
||||
#define CODEWORD_SHIFT 2
|
||||
#else
|
||||
#define CODEWORD_SHIFT 3
|
||||
#endif
|
||||
|
||||
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( "%02x ", ofs );
|
||||
}
|
||||
printf( "\n" );
|
||||
|
||||
runningcount_bits = 0;
|
||||
|
||||
// This tells the interrupt we have data.
|
||||
quadsetcount = qso - quadsets + 0;
|
||||
printf( "--- %d [%d] %d\n", lora_symbols_count, quadsetcount, CHIPSSPREAD/4 );
|
||||
quadsetplace = 0;
|
||||
#ifdef TESTSTRAP
|
||||
while(1)
|
||||
{
|
||||
slc_isr( 0 );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
|
||||
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 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.
|
||||
|
||||
**/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
const double center_frequency = 904.5;
|
||||
const double bw = .125;
|
||||
const uint32_t memory_offset = 0x20000;
|
||||
#define SF_NUMBER 9
|
||||
#define SF_SYMBOL_TIME 0.000001
|
||||
#define MEM_MAX_BYTES 68000
|
||||
|
||||
#if SF_NUMBER < 7
|
||||
#warning SF6 still does not work :(
|
||||
#endif
|
||||
|
||||
#define SPI_DIV 1
|
||||
|
||||
// Funny modes:
|
||||
/// 80MHz, SF8, SPI_DIV 5 @903.9/904.1 produces hilarious mirror images around 904.0
|
||||
|
||||
#if MAIN_MHZ == 80
|
||||
const double sample_rate = 1040.0/13.0/SPI_DIV;
|
||||
|
||||
#elif MAIN_MHZ == 115
|
||||
const double sample_rate = 1040.0/9.0/SPI_DIV;
|
||||
|
||||
#elif MAIN_MHZ == 52
|
||||
const double sample_rate = 1040.0/20.0/SPI_DIV;
|
||||
|
||||
#elif MAIN_MHZ == 173
|
||||
const double sample_rate = 1040.0/6.0/SPI_DIV;
|
||||
|
||||
#else
|
||||
#error Unknown Clock Rate
|
||||
#endif
|
||||
|
||||
|
||||
#include "../../lib/rf_data_gen.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
return gen_buffer_files();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
all : chirpbuff.dat.flash
|
||||
|
||||
SUBMODULE=YES
|
||||
SRCPREFIX=../nosdk8266/
|
||||
MAIN_MHZ=80
|
||||
SRCS=main.c
|
||||
DEPS=chirpbuffinfo.h
|
||||
COMPILECOUNT=$(shell cat compilecount.txt || true)
|
||||
BUILDCOUNTCMD=echo 1+0$(COMPILECOUNT) | bc > compilecount.txt | true Compiled $(COMPILECOUNT) times
|
||||
CFLAGS=-I../../lib -I..
|
||||
|
||||
include ../nosdk8266/Makefile
|
||||
|
||||
rf_data_gen : rf_data_gen.c
|
||||
gcc -o $@ $^ -lm -DMAIN_MHZ=$(MAIN_MHZ)
|
||||
|
||||
chirpbuffinfo.h : chirpbuff.dat
|
||||
|
||||
teststrap : main.c chirpbuff.dat
|
||||
gcc -o teststrap main.c -DTESTSTRAP -I../nosdk8266/include
|
||||
|
||||
|
||||
chirpbuff.dat : rf_data_gen
|
||||
./rf_data_gen
|
||||
|
||||
chirpbuff.dat.flash : chirpbuff.dat
|
||||
$(ESPUTIL) -b 115200 flash 0x20000 chirpbuff.dat
|
||||
|
||||
cleanall : clean
|
||||
rm -rf chirpbuff.h rf_data_gen chirpbuff.dat chirpbuffinfo.h
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# ESP8266 / ESP8285 Lora Transmitter
|
||||
|
||||
Connect a small length of wire to the "RX" pin on your ESP8266, then it will transmit SF10 LoRa messages at 904.6MHz, with channel width of 500kHz.
|
||||
|
||||
Be sure to configure your receiver to specifically use SF10, 500kHz, on 904.6MHz. Many commercial receivers cannot automatically negotiate 500kHz channels.
|
||||
@@ -0,0 +1 @@
|
||||
46
|
||||
@@ -0,0 +1,294 @@
|
||||
/**
|
||||
|
||||
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.
|
||||
|
||||
**/
|
||||
|
||||
#include "esp8266_auxrom.h"
|
||||
#include "eagle_soc.h"
|
||||
#include "nosdk8266.h"
|
||||
#include "esp8266_rom.h"
|
||||
|
||||
// TODO: Use float number (related to 8) to fix the drift
|
||||
#define call_delay_us(time) { asm volatile("mov.n a2, %0\n_call0 delay4clk" : : "r"(time * (MAIN_MHZ / 8)) : "a2" ); }
|
||||
|
||||
#include "ets_sys.h"
|
||||
#include "pin_mux_register.h"
|
||||
#include "slc_register.h"
|
||||
#include "dmastuff.h"
|
||||
#include "chirpbuffinfo.h"
|
||||
#include "LoRa-SDR-Code.h"
|
||||
|
||||
#define DMABUFFERDEPTH 3
|
||||
//These contol the speed at which the bus comms.
|
||||
#define WS_I2S_BCK SPI_DIV //Can't be less than 1.
|
||||
#define WS_I2S_DIV 1
|
||||
|
||||
#ifndef TESTSTRAP
|
||||
#include "esp8266_i2s_setup.h"
|
||||
#endif
|
||||
|
||||
uint32_t chirpbuffUP[CHIRPLENGTH_WORDS_WITH_PADDING];
|
||||
uint32_t chirpbuffDOWN[CHIRPLENGTH_WORDS_WITH_PADDING];
|
||||
uint32_t dummy[DMA_SIZE_WORDS];
|
||||
|
||||
volatile int fxcycle;
|
||||
int etx;
|
||||
|
||||
// This "should" be big enough to store up to 255 bytes of payload in a LoRa message.
|
||||
#define MAX_SYMBOLS 532
|
||||
|
||||
|
||||
// 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<<SF_NUMBER)
|
||||
|
||||
#define PREAMBLE_CHIRPS 10
|
||||
#define CODEWORD_LENGTH 2
|
||||
|
||||
uint32_t quadsetcount;
|
||||
int32_t quadsets[MAX_SYMBOLS*4+PREAMBLE_CHIRPS*4+9+CODEWORD_LENGTH*4];
|
||||
|
||||
int32_t * AddChirp( int32_t * qso, int offset, int verneer )
|
||||
{
|
||||
offset = offset * CHIPSSPREAD / (MARK_FROM_SF0);
|
||||
offset += verneer;
|
||||
*(qso++) = (CHIPSSPREAD * 0 / 4 + offset + CHIPSSPREAD ) % CHIPSSPREAD;
|
||||
*(qso++) = (CHIPSSPREAD * 1 / 4 + offset + CHIPSSPREAD ) % CHIPSSPREAD;
|
||||
*(qso++) = (CHIPSSPREAD * 2 / 4 + offset + CHIPSSPREAD ) % CHIPSSPREAD;
|
||||
*(qso++) = (CHIPSSPREAD * 3 / 4 + offset + CHIPSSPREAD ) % CHIPSSPREAD;
|
||||
return qso;
|
||||
}
|
||||
|
||||
|
||||
volatile int quadsetplace = -1;
|
||||
|
||||
int runningcount_bits = 0;
|
||||
|
||||
void slc_isr(void * v) {
|
||||
|
||||
uint32_t * sendbuff = 0;
|
||||
uint32_t sendlen = 0;
|
||||
struct sdio_queue *finishedDesc;
|
||||
// slc_intr_status = READ_PERI_REG(SLC_INT_STATUS); -> We should check to make sure we are SLC_RX_EOF_INT_ST, but we are only getting one interrupt.
|
||||
|
||||
WRITE_PERI_REG(SLC_INT_CLR, 0xffffffff);
|
||||
finishedDesc=(struct sdio_queue*)READ_PERI_REG(SLC_RX_EOF_DES_ADDR);
|
||||
|
||||
etx++;
|
||||
|
||||
if( quadsetplace < 0 )
|
||||
{
|
||||
goto dump0;
|
||||
}
|
||||
|
||||
// LoRa symbols are in quarters of a chirp.
|
||||
if( fxcycle>= NUM_DMAS_PER_QUARTER_CHIRP )
|
||||
{
|
||||
fxcycle = 0;
|
||||
quadsetplace++;
|
||||
if( quadsetplace >= quadsetcount ) goto dump0;
|
||||
}
|
||||
|
||||
int symbol = quadsets[quadsetplace];
|
||||
|
||||
// Select down- or up-chirp.
|
||||
if( symbol < 0 )
|
||||
{
|
||||
int word = fxcycle * DMA_SIZE_WORDS - symbol - 1;
|
||||
if( word >= CHIPSSPREAD ) word -= CHIPSSPREAD;
|
||||
word++;
|
||||
sendbuff = (chirpbuffDOWN + word);
|
||||
}
|
||||
else
|
||||
{
|
||||
int word = fxcycle * DMA_SIZE_WORDS + symbol;
|
||||
if( word >= CHIPSSPREAD ) word -= CHIPSSPREAD;
|
||||
sendbuff = (chirpbuffUP + word);
|
||||
}
|
||||
|
||||
#ifndef FOUND_PERFECT_DIVISOR
|
||||
// Sometimes we do the full length, of all of the needed DMAs
|
||||
// Sometimes we overshoot the time window, so we peel off 4 bytes.
|
||||
//
|
||||
// Very few combinations of clock rate, divisor, etc can produce
|
||||
// perfect divisors. Most notably 52MHz, /2 SF9 can produce a perfect
|
||||
// divisor. While this is very tidy and beautiful that the
|
||||
// words would align perfectly, the actual difference it makes on
|
||||
// LoRa's ability to receive the message is minimal.
|
||||
//
|
||||
// Additionally, 80MHz /2 SF7 can produce a perfect divisor.
|
||||
int running_bits_after = runningcount_bits + DMA_SIZE_WORDS*32;
|
||||
int overflow = running_bits_after - IDEAL_QUARTER_CHIRP_LENGTH_BITS;
|
||||
if( overflow >= 0 )
|
||||
{
|
||||
int overflow_amount = overflow / 32;
|
||||
int overflow_remainder = overflow % 32;
|
||||
sendlen = DMA_SIZE_WORDS*4 - 4*overflow_amount;
|
||||
runningcount_bits = overflow_remainder;
|
||||
|
||||
// XXX TODO: Why can't I put the logic for advancing the group in here?
|
||||
}
|
||||
else
|
||||
{
|
||||
sendlen = DMA_SIZE_WORDS*4;
|
||||
runningcount_bits = running_bits_after;
|
||||
}
|
||||
#else
|
||||
sendlen = DMA_SIZE_WORDS*4;
|
||||
#endif
|
||||
|
||||
finishedDesc->buf_ptr = (uint32_t)sendbuff;
|
||||
finishedDesc->datalen = sendlen;
|
||||
|
||||
fxcycle++;
|
||||
return;
|
||||
|
||||
|
||||
dump0:
|
||||
// This location just always reads as zeroes.
|
||||
finishedDesc->buf_ptr = (uint32_t)dummy;
|
||||
quadsetplace = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// We store the bit pattern at flash:0x20000, so we don't have to constantly
|
||||
// re-write it when working on code.
|
||||
SPIRead( MEMORY_START_OFFSET_BYTES, chirpbuffUP, sizeof( chirpbuffUP ) );
|
||||
SPIRead( REVERSE_START_OFFSET_BYTES, chirpbuffDOWN, sizeof( chirpbuffDOWN ) );
|
||||
memset( dummy, 0, sizeof( dummy ) );
|
||||
|
||||
// Don't crank up clock speed til we're done with flash.
|
||||
nosdk8266_init();
|
||||
|
||||
|
||||
int i = 0;
|
||||
fxcycle = 0;
|
||||
etx = 0;
|
||||
|
||||
testi2s_init( dummy );
|
||||
|
||||
int frame = 0;
|
||||
uint16_t lora_symbols[MAX_SYMBOLS];
|
||||
int lora_symbols_count;
|
||||
|
||||
while(1) {
|
||||
//12x this speed.
|
||||
frame++;
|
||||
|
||||
PIN_OUT_SET = _BV(2); //Turn GPIO2 light off.
|
||||
//call_delay_us(1000000);
|
||||
printf("ETX: %d %08x\n", fxcycle, chirpbuffUP[10] );
|
||||
PIN_OUT_CLEAR = _BV(2); //Turn GPIO2 light on.
|
||||
call_delay_us(1000000);
|
||||
|
||||
// Just some random data.
|
||||
uint8_t payload_in[259] = { 0xbb, 0xcc, 0xde, 0x55, 0x22,};
|
||||
int payload_in_size = 6;
|
||||
|
||||
static int msgno = 0;
|
||||
payload_in[4] = msgno++;
|
||||
|
||||
lora_symbols_count = 0;
|
||||
int r = CreateMessageFromPayload( lora_symbols, &lora_symbols_count, MAX_SYMBOLS, SF_NUMBER, 4, payload_in, payload_in_size );
|
||||
|
||||
if( r < 0 )
|
||||
{
|
||||
printf( "Failed to generate message (%d)\n", r );
|
||||
// Failed
|
||||
continue;
|
||||
}
|
||||
|
||||
int j;
|
||||
|
||||
quadsetcount = 0;
|
||||
int32_t * qso = quadsets;
|
||||
for( j = 0; j < PREAMBLE_CHIRPS; j++ )
|
||||
{
|
||||
qso = AddChirp( qso, 0, 0 );
|
||||
}
|
||||
|
||||
uint8_t syncword = 0x43;
|
||||
#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];
|
||||
qso = AddChirp( qso, ofs, 0 );
|
||||
printf( "%02x ", ofs );
|
||||
}
|
||||
printf( "\n" );
|
||||
|
||||
runningcount_bits = 0;
|
||||
|
||||
// This tells the interrupt we have data.
|
||||
quadsetcount = qso - quadsets + 0;
|
||||
printf( "--- %d [%d] %d\n", lora_symbols_count, quadsetcount, CHIPSSPREAD/4 );
|
||||
quadsetplace = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
MIT 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 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.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
const double center_frequency = 904.6;
|
||||
const double bw = .5;
|
||||
const uint32_t memory_offset = 0x20000;
|
||||
#define SF_NUMBER 10
|
||||
#define SF_SYMBOL_TIME 0.00000025
|
||||
#define MEM_MAX_BYTES 68000
|
||||
|
||||
#if SF_NUMBER < 7
|
||||
#warning SF6 still does not work :(
|
||||
#endif
|
||||
|
||||
#define SPI_DIV 1
|
||||
|
||||
// Funny modes:
|
||||
/// 80MHz, SF8, SPI_DIV 5 @903.9/904.1 produces hilarious mirror images around 904.0
|
||||
|
||||
#if MAIN_MHZ == 80
|
||||
const double sample_rate = 1040.0/13.0/SPI_DIV;
|
||||
|
||||
#elif MAIN_MHZ == 115
|
||||
const double sample_rate = 1040.0/9.0/SPI_DIV;
|
||||
|
||||
#elif MAIN_MHZ == 52
|
||||
const double sample_rate = 1040.0/20.0/SPI_DIV;
|
||||
|
||||
#elif MAIN_MHZ == 173
|
||||
const double sample_rate = 1040.0/6.0/SPI_DIV;
|
||||
|
||||
#else
|
||||
#error Unknown Clock Rate
|
||||
#endif
|
||||
|
||||
|
||||
#include "../../lib/rf_data_gen.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
return gen_buffer_files();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
all : chirpbuff.dat.flash
|
||||
|
||||
SUBMODULE=YES
|
||||
SRCPREFIX=../nosdk8266/
|
||||
MAIN_MHZ=173
|
||||
SRCS=main.c
|
||||
DEPS=chirpbuffinfo.h
|
||||
COMPILECOUNT=$(shell cat compilecount.txt || true)
|
||||
BUILDCOUNTCMD=echo 1+0$(COMPILECOUNT) | bc > compilecount.txt | true Compiled $(COMPILECOUNT) times
|
||||
CFLAGS=-I../../lib -I..
|
||||
|
||||
include ../nosdk8266/Makefile
|
||||
|
||||
rf_data_gen : rf_data_gen.c
|
||||
gcc -o $@ $^ -lm -DMAIN_MHZ=$(MAIN_MHZ)
|
||||
|
||||
chirpbuffinfo.h : chirpbuff.dat
|
||||
|
||||
teststrap : main.c chirpbuff.dat
|
||||
gcc -o teststrap main.c -DTESTSTRAP -I../nosdk8266/include
|
||||
|
||||
|
||||
chirpbuff.dat : rf_data_gen
|
||||
./rf_data_gen
|
||||
|
||||
chirpbuff.dat.flash : chirpbuff.dat
|
||||
$(ESPUTIL) -b 115200 flash 0x20000 chirpbuff.dat
|
||||
|
||||
cleanall : clean
|
||||
rm -rf chirpbuff.h rf_data_gen chirpbuff.dat chirpbuffinfo.h
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# ESP8266 / ESP8285 TheThings Network LoRaWAN transmitter.
|
||||
|
||||
Same as the others - connect a small length of wire to the "RX" pin on your ESP8266, then it will transmit SF7 LoRa messages at 904.1MHz.
|
||||
|
||||
But this, has the code in main() to send frames to thethings.network as valid LoRaWAN frames.
|
||||
|
||||
|
||||
On thethings.network,
|
||||
|
||||
1. Generate a new app.
|
||||
2. Register a new device.
|
||||
3. Select `Enter end device specifics manually`
|
||||
4. Select US Plan 902-928, FSB2 (Used by TTN)
|
||||
5. LoRaWAN Specification 1.0.0
|
||||
6. TS001 Technical Specificaiton 1.0.0
|
||||
7. "Show Advanced activation, LoRaWAN class and cluster settings"
|
||||
8. Activation by Personalization
|
||||
9. No addtional LoRaWAN class capabilities (class A only)
|
||||
10. Use Network's default MAC settings.
|
||||
11. Generate new EUI.
|
||||
12. Generate new Device ID.
|
||||
|
||||
Add the device, it may make sense to back out to the menu so you can copy the LSB for the address, and the code for MSB for keys.
|
||||
|
||||
Replace the `payload_key`, `network_skey`, and `devaddress` in `main.c`
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
117
|
||||
@@ -0,0 +1,333 @@
|
||||
/**
|
||||
|
||||
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.
|
||||
|
||||
**/
|
||||
|
||||
// Transmit LoRaWAN Packets from an ESP8266 - be sure to fill in your
|
||||
// payload_key, network_skey and devaddress
|
||||
|
||||
#include "esp8266_auxrom.h"
|
||||
#include "eagle_soc.h"
|
||||
#include "nosdk8266.h"
|
||||
#include "esp8266_rom.h"
|
||||
#include "ets_sys.h"
|
||||
#include "pin_mux_register.h"
|
||||
#include "chirpbuffinfo.h"
|
||||
#include "LoRa-SDR-Code.h"
|
||||
|
||||
|
||||
#define DMABUFFERDEPTH 3
|
||||
//These contol the speed at which the bus comms.
|
||||
#define WS_I2S_BCK SPI_DIV //Can't be less than 1.
|
||||
#define WS_I2S_DIV 1
|
||||
|
||||
#include "esp8266_i2s_setup.h"
|
||||
|
||||
#include "lorawan_simple.h"
|
||||
|
||||
|
||||
uint32_t chirpbuffUP[CHIRPLENGTH_WORDS_WITH_PADDING];
|
||||
uint32_t chirpbuffDOWN[CHIRPLENGTH_WORDS_WITH_PADDING];
|
||||
uint32_t dummy[DMA_SIZE_WORDS];
|
||||
|
||||
volatile int fxcycle;
|
||||
int etx;
|
||||
|
||||
// Practical limit because of RAM usage. But this should be able to hold a full-sized (255-byte) LoRa packet.
|
||||
#define MAX_SYMBOLS 532
|
||||
|
||||
|
||||
// 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<<SF_NUMBER) // SF7
|
||||
|
||||
#define PREAMBLE_CHIRPS 10
|
||||
#define CODEWORD_LENGTH 2
|
||||
|
||||
uint32_t quadsetcount;
|
||||
int32_t quadsets[MAX_SYMBOLS*4+PREAMBLE_CHIRPS*4+9+CODEWORD_LENGTH*4];
|
||||
|
||||
int32_t * AddChirp( int32_t * qso, int offset, int verneer )
|
||||
{
|
||||
offset = offset * CHIPSSPREAD / (MARK_FROM_SF0);
|
||||
offset += verneer;
|
||||
*(qso++) = (CHIPSSPREAD * 0 / 4 + offset + CHIPSSPREAD ) % CHIPSSPREAD;
|
||||
*(qso++) = (CHIPSSPREAD * 1 / 4 + offset + CHIPSSPREAD ) % CHIPSSPREAD;
|
||||
*(qso++) = (CHIPSSPREAD * 2 / 4 + offset + CHIPSSPREAD ) % CHIPSSPREAD;
|
||||
*(qso++) = (CHIPSSPREAD * 3 / 4 + offset + CHIPSSPREAD ) % CHIPSSPREAD;
|
||||
return qso;
|
||||
}
|
||||
|
||||
|
||||
volatile int quadsetplace = -1;
|
||||
|
||||
int runningcount_bits = 0;
|
||||
|
||||
// TODO: Use float number (related to 8) to fix the drift
|
||||
#define call_delay_us(time) { asm volatile("mov.n a2, %0\n_call0 delay4clk" : : "r"(time * (MAIN_MHZ / 8)) : "a2" ); }
|
||||
|
||||
void slc_isr(void * v) {
|
||||
|
||||
uint32_t * sendbuff = 0;
|
||||
uint32_t sendlen = 0;
|
||||
struct sdio_queue *finishedDesc;
|
||||
|
||||
WRITE_PERI_REG(SLC_INT_CLR, 0xffffffff);
|
||||
finishedDesc=(struct sdio_queue*)READ_PERI_REG(SLC_RX_EOF_DES_ADDR);
|
||||
|
||||
etx++;
|
||||
|
||||
if( quadsetplace < 0 )
|
||||
{
|
||||
goto dump0;
|
||||
}
|
||||
|
||||
// LoRa symbols are in quarters of a chirp.
|
||||
if( fxcycle>= NUM_DMAS_PER_QUARTER_CHIRP )
|
||||
{
|
||||
fxcycle = 0;
|
||||
quadsetplace++;
|
||||
if( quadsetplace >= quadsetcount ) goto dump0;
|
||||
}
|
||||
|
||||
int symbol = quadsets[quadsetplace];
|
||||
|
||||
// Select down- or up-chirp.
|
||||
if( symbol < 0 )
|
||||
{
|
||||
int word = fxcycle * DMA_SIZE_WORDS - symbol - 1;
|
||||
if( word >= CHIPSSPREAD ) word -= CHIPSSPREAD;
|
||||
word++;
|
||||
sendbuff = (chirpbuffDOWN + word);
|
||||
}
|
||||
else
|
||||
{
|
||||
int word = fxcycle * DMA_SIZE_WORDS + symbol;
|
||||
if( word >= CHIPSSPREAD ) word -= CHIPSSPREAD;
|
||||
sendbuff = (chirpbuffUP + word);
|
||||
}
|
||||
|
||||
#ifndef FOUND_PERFECT_DIVISOR
|
||||
// Sometimes we do the full length, of all of the needed DMAs
|
||||
// Sometimes we overshoot the time window, so we peel off 4 bytes.
|
||||
//
|
||||
// Very few combinations of clock rate, divisor, etc can produce
|
||||
// perfect divisors. Most notably 52MHz, /2 SF9 can produce a perfect
|
||||
// divisor. While this is very tidy and beautiful that the
|
||||
// words would align perfectly, the actual difference it makes on
|
||||
// LoRa's ability to receive the message is minimal.
|
||||
//
|
||||
// Additionally, 80MHz /2 SF7 can produce a perfect divisor.
|
||||
int running_bits_after = runningcount_bits + DMA_SIZE_WORDS*32;
|
||||
int overflow = running_bits_after - IDEAL_QUARTER_CHIRP_LENGTH_BITS;
|
||||
if( overflow >= 0 )
|
||||
{
|
||||
int overflow_amount = overflow / 32;
|
||||
int overflow_remainder = overflow % 32;
|
||||
sendlen = DMA_SIZE_WORDS*4 - 4*overflow_amount;
|
||||
runningcount_bits = overflow_remainder;
|
||||
|
||||
// XXX TODO: Why can't I put the logic for advancing the group in here?
|
||||
}
|
||||
else
|
||||
{
|
||||
sendlen = DMA_SIZE_WORDS*4;
|
||||
runningcount_bits = running_bits_after;
|
||||
}
|
||||
#else
|
||||
sendlen = DMA_SIZE_WORDS*4;
|
||||
#endif
|
||||
|
||||
finishedDesc->buf_ptr = (uint32_t)sendbuff;
|
||||
finishedDesc->datalen = sendlen;
|
||||
|
||||
fxcycle++;
|
||||
return;
|
||||
|
||||
|
||||
dump0:
|
||||
// This location just always reads as zeroes.
|
||||
finishedDesc->buf_ptr = (uint32_t)dummy;
|
||||
quadsetplace = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// We store the bit pattern at flash:0x20000, so we don't have to constantly
|
||||
// re-write it when working on code.
|
||||
SPIRead( MEMORY_START_OFFSET_BYTES, chirpbuffUP, sizeof( chirpbuffUP ) );
|
||||
SPIRead( REVERSE_START_OFFSET_BYTES, chirpbuffDOWN, sizeof( chirpbuffDOWN ) );
|
||||
memset( dummy, 0, sizeof( dummy ) );
|
||||
|
||||
// Don't crank up clock speed til we're done with flash.
|
||||
nosdk8266_init();
|
||||
|
||||
|
||||
int i = 0;
|
||||
fxcycle = 0;
|
||||
etx = 0;
|
||||
// Configure GPIO5 (TX) and GPIO2 (LED)
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U,FUNC_GPIO2);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U,FUNC_GPIO5);
|
||||
PIN_DIR_OUTPUT = _BV(2); //Enable GPIO2 light off.
|
||||
|
||||
// Run the I2S bus at 1040/6 = 173.333 MHz.
|
||||
// It looks like, at least on my part, if I try running
|
||||
// hotter it can get to 1040/5.1 but not all the way to
|
||||
// 5 so it's unstable there.
|
||||
|
||||
testi2s_init( dummy );
|
||||
|
||||
int frame = 0;
|
||||
uint16_t lora_symbols[MAX_SYMBOLS];
|
||||
int lora_symbols_count;
|
||||
|
||||
frame = 0;
|
||||
|
||||
while(1) {
|
||||
//12x this speed.
|
||||
frame++;
|
||||
|
||||
PIN_OUT_SET = _BV(2); //Turn GPIO2 light off.
|
||||
printf("ETX: %d %08x\n", fxcycle, chirpbuffUP[10] );
|
||||
PIN_OUT_CLEAR = _BV(2); //Turn GPIO2 light on.
|
||||
call_delay_us(5000000);
|
||||
|
||||
// Send a message with LoraWan. Formatted specifically for thethings.network.
|
||||
uint8_t inner_payload_raw[20] = { 'T', 'e', 's', 't', '0', '0', '0', '0', ' ', ' ', ' ', ' ', ' ', ' ', ' ' };
|
||||
inner_payload_raw[4] = ((frame/1000)%10)+'0';
|
||||
inner_payload_raw[5] = ((frame/100)%10)+'0';
|
||||
inner_payload_raw[6] = ((frame/10)%10)+'0';
|
||||
inner_payload_raw[7] = (frame%10)+'0';
|
||||
int inner_payload_len = 20;
|
||||
|
||||
// Get these from your thethings.network console.
|
||||
// GENERAL NOTE: When addinga new device, go to General Settings -> Network Layer -> Advanced MAC Settings -> Resets frame counters [check]
|
||||
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)
|
||||
#warning Please set payload_key, network_skey and devaddress
|
||||
|
||||
// Just some random data.
|
||||
uint8_t raw_payload_with_b0[259+8] = { };
|
||||
uint8_t * raw_payload = raw_payload_with_b0 + 16;
|
||||
uint8_t * pl = raw_payload;
|
||||
int raw_payload_size = 0;
|
||||
|
||||
pl += GenerateLoRaWANPacket( raw_payload_with_b0, inner_payload_raw, inner_payload_len, payload_key, network_skey, devaddress, frame);
|
||||
|
||||
raw_payload_size = pl - raw_payload;
|
||||
|
||||
printf( "Length: %d\n", raw_payload_size );
|
||||
|
||||
for( i = 0; i < raw_payload_size; i++ )
|
||||
printf( "%02x ", raw_payload[i] );
|
||||
|
||||
printf( "\n" );
|
||||
|
||||
lora_symbols_count = 0;
|
||||
int r = CreateMessageFromPayload( lora_symbols, &lora_symbols_count, MAX_SYMBOLS, SF_NUMBER, 4, raw_payload, raw_payload_size );
|
||||
|
||||
if( r < 0 )
|
||||
{
|
||||
printf( "Failed to generate message (%d)\n", r );
|
||||
// Failed
|
||||
continue;
|
||||
}
|
||||
|
||||
int j;
|
||||
|
||||
quadsetcount = 0;
|
||||
int32_t * qso = quadsets;
|
||||
for( j = 0; j < PREAMBLE_CHIRPS; j++ )
|
||||
{
|
||||
qso = AddChirp( qso, 0, 0 );
|
||||
}
|
||||
|
||||
uint8_t syncword = 0x43;
|
||||
|
||||
#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( "%02x ", ofs );
|
||||
}
|
||||
printf( "\n" );
|
||||
|
||||
runningcount_bits = 0;
|
||||
|
||||
// This tells the interrupt we have data.
|
||||
quadsetcount = qso - quadsets + 0;
|
||||
printf( "--- %d [%d] %d frame %08x\n", lora_symbols_count, quadsetcount, CHIPSSPREAD/4, frame );
|
||||
quadsetplace = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
Known Reference
|
||||
QF/ZDCaAGwAB1Rwa9Hh7AF9mVtq3 -> (CRC 41445, SF10 CR 4/5, 904.5MHz) -> App Payload 1Rwa9Hh7AF8= -> Mikrotik address 26 0C D9 5F ->
|
||||
From the things network: QF/ZDCaAGwAB1Rwa9Hh7AF9mVtq3 "frm_payload": "1Rwa9Hh7AF8=" // "mic": "Zlbatw==",
|
||||
|
||||
// 8 A's. 0x41 x 8
|
||||
|
||||
// Full raw packet
|
||||
405fd90c26801b0001
|
||||
d51c1af4787b005f
|
||||
6656dab7
|
||||
|
||||
// My test
|
||||
405fd90c26801b0001
|
||||
d51c1af4787b005f
|
||||
6656dab7
|
||||
|
||||
{
|
||||
"name": "as.up.data.forward",
|
||||
"time": "2024-02-18T03:25:33.806043236Z",
|
||||
"identifiers": [
|
||||
{
|
||||
"device_ids": {
|
||||
"device_id": "eui-70b3d57ed00651da",
|
||||
"application_ids": {
|
||||
"application_id": "cursed-esp8266"
|
||||
},
|
||||
"dev_eui": "70B3D57ED00651DA",
|
||||
"dev_addr": "260CD95F"
|
||||
}
|
||||
}
|
||||
],
|
||||
"data": {
|
||||
"@type": "type.googleapis.com/ttn.lorawan.v3.ApplicationUp",
|
||||
"end_device_ids": {
|
||||
"device_id": "eui-70b3d57ed00651da",
|
||||
"application_ids": {
|
||||
"application_id": "cursed-esp8266"
|
||||
},
|
||||
"dev_eui": "70B3D57ED00651DA",
|
||||
"dev_addr": "260CD95F"
|
||||
},
|
||||
"correlation_ids": [
|
||||
"gs:uplink:01HPX3YSGKBGH71N3Q8T2BGJCM"
|
||||
],
|
||||
"received_at": "2024-02-18T03:25:33.803070864Z",
|
||||
"uplink_message": {
|
||||
"f_port": 1,
|
||||
"f_cnt": 27,
|
||||
"frm_payload": "QUFBQUFBQUE=",
|
||||
"rx_metadata": [
|
||||
{
|
||||
"gateway_ids": {
|
||||
"gateway_id": "eui-343632383e002300",
|
||||
"eui": "343632383E002300"
|
||||
},
|
||||
"time": "2024-02-18T03:25:25.274488Z",
|
||||
"timestamp": 1948262652,
|
||||
"rssi": -33,
|
||||
"channel_rssi": -33,
|
||||
"snr": 12.5,
|
||||
"uplink_token": "CiIKIAoUZXVpLTM0MzYzMjM4M2UwMDIzMDASCDQ2Mjg+ACMAEPzBgKEHGgwIrfHFrgYQ+IemmAIg4LCD7Nk4",
|
||||
"channel_index": 3,
|
||||
"received_at": "2024-02-18T03:25:33.573997023Z"
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"data_rate": {
|
||||
"lora": {
|
||||
"bandwidth": 125000,
|
||||
"spreading_factor": 10,
|
||||
"coding_rate": "4/5"
|
||||
}
|
||||
},
|
||||
"frequency": "904500000",
|
||||
"timestamp": 1948262652,
|
||||
"time": "2024-02-18T03:25:25.274488Z"
|
||||
},
|
||||
"received_at": "2024-02-18T03:25:33.589092783Z",
|
||||
"consumed_airtime": "0.370688s",
|
||||
"network_ids": {
|
||||
"net_id": "000013",
|
||||
"ns_id": "EC656E0000000182",
|
||||
"tenant_id": "ttn",
|
||||
"cluster_id": "nam1",
|
||||
"cluster_address": "nam1.cloud.thethings.network"
|
||||
}
|
||||
}
|
||||
},
|
||||
"correlation_ids": [
|
||||
"gs:uplink:01HPX3YSGKBGH71N3Q8T2BGJCM"
|
||||
],
|
||||
"origin": "ip-10-101-7-121.us-west-1.compute.internal",
|
||||
"context": {
|
||||
"tenant-id": "CgN0dG4="
|
||||
},
|
||||
"visibility": {
|
||||
"rights": [
|
||||
"RIGHT_APPLICATION_TRAFFIC_READ"
|
||||
]
|
||||
},
|
||||
"unique_id": "01HPX3YSQE3XHB4JGNEBQYAB2E"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{
|
||||
"name": "gs.up.receive",
|
||||
"time": "2024-02-18T03:25:33.588003627Z",
|
||||
"identifiers": [
|
||||
{
|
||||
"gateway_ids": {
|
||||
"gateway_id": "eui-343632383e002300",
|
||||
"eui": "343632383E002300"
|
||||
}
|
||||
}
|
||||
],
|
||||
"data": {
|
||||
"@type": "type.googleapis.com/ttn.lorawan.v3.GatewayUplinkMessage",
|
||||
"message": {
|
||||
"raw_payload": "QF/ZDCaAGwAB1Rwa9Hh7AF9mVtq3",
|
||||
"payload": {
|
||||
"m_hdr": {
|
||||
"m_type": "UNCONFIRMED_UP"
|
||||
},
|
||||
"mic": "Zlbatw==",
|
||||
"mac_payload": {
|
||||
"f_hdr": {
|
||||
"dev_addr": "260CD95F",
|
||||
"f_ctrl": {
|
||||
"adr": true
|
||||
},
|
||||
"f_cnt": 27
|
||||
},
|
||||
"f_port": 1,
|
||||
"frm_payload": "1Rwa9Hh7AF8="
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"data_rate": {
|
||||
"lora": {
|
||||
"bandwidth": 125000,
|
||||
"spreading_factor": 10,
|
||||
"coding_rate": "4/5"
|
||||
}
|
||||
},
|
||||
"frequency": "904500000",
|
||||
"timestamp": 1948262652,
|
||||
"time": "2024-02-18T03:25:25.274488Z"
|
||||
},
|
||||
"rx_metadata": [
|
||||
{
|
||||
"gateway_ids": {
|
||||
"gateway_id": "eui-343632383e002300",
|
||||
"eui": "343632383E002300"
|
||||
},
|
||||
"time": "2024-02-18T03:25:25.274488Z",
|
||||
"timestamp": 1948262652,
|
||||
"rssi": -33,
|
||||
"channel_rssi": -33,
|
||||
"snr": 12.5,
|
||||
"uplink_token": "CiIKIAoUZXVpLTM0MzYzMjM4M2UwMDIzMDASCDQ2Mjg+ACMAEPzBgKEHGgwIrfHFrgYQ+IemmAIg4LCD7Nk4",
|
||||
"channel_index": 3,
|
||||
"received_at": "2024-02-18T03:25:33.573997023Z"
|
||||
}
|
||||
],
|
||||
"received_at": "2024-02-18T03:25:33.587826168Z",
|
||||
"correlation_ids": [
|
||||
"gs:uplink:01HPX3YSGKBGH71N3Q8T2BGJCM"
|
||||
],
|
||||
"crc_status": true
|
||||
},
|
||||
"band_id": "US_902_928"
|
||||
},
|
||||
"correlation_ids": [
|
||||
"gs:uplink:01HPX3YSGKBGH71N3Q8T2BGJCM"
|
||||
],
|
||||
"origin": "ip-10-101-4-161.us-west-1.compute.internal",
|
||||
"context": {
|
||||
"tenant-id": "CgN0dG4="
|
||||
},
|
||||
"visibility": {
|
||||
"rights": [
|
||||
"RIGHT_GATEWAY_TRAFFIC_READ"
|
||||
]
|
||||
},
|
||||
"unique_id": "01HPX3YSGMTSH0JBWT8BEZQJRC"
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
MIT 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 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.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
const double center_frequency = 904.1;
|
||||
const double bw = .125;
|
||||
const uint32_t memory_offset = 0x20000;
|
||||
#define SF_NUMBER 7
|
||||
#define SF_SYMBOL_TIME 0.000001
|
||||
#define MEM_MAX_BYTES 68000
|
||||
|
||||
#if SF_NUMBER < 7
|
||||
#warning SF6 still does not work :(
|
||||
#endif
|
||||
|
||||
#define SPI_DIV 1
|
||||
|
||||
// Funny modes:
|
||||
/// 80MHz, SF8, SPI_DIV 5 @903.9/904.1 produces hilarious mirror images around 904.0
|
||||
|
||||
#if MAIN_MHZ == 80
|
||||
const double sample_rate = 1040.0/13.0/SPI_DIV;
|
||||
|
||||
#elif MAIN_MHZ == 115
|
||||
const double sample_rate = 1040.0/9.0/SPI_DIV;
|
||||
|
||||
#elif MAIN_MHZ == 52
|
||||
const double sample_rate = 1040.0/20.0/SPI_DIV;
|
||||
|
||||
#elif MAIN_MHZ == 173
|
||||
const double sample_rate = 1040.0/6.0/SPI_DIV;
|
||||
|
||||
#else
|
||||
#error Unknown Clock Rate
|
||||
#endif
|
||||
|
||||
|
||||
#include "../../lib/rf_data_gen.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
return gen_buffer_files();
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
all : flash
|
||||
|
||||
SUBMODULE=YES
|
||||
SRCPREFIX=../nosdk8266/
|
||||
MAIN_MHZ=173
|
||||
SRCS=main.c
|
||||
DEPS=samples.h
|
||||
COMPILECOUNT=$(shell cat compilecount.txt || true)
|
||||
BUILDCOUNTCMD=echo 1+0$(COMPILECOUNT) | bc > compilecount.txt | true Compiled $(COMPILECOUNT) times
|
||||
CFLAGS=-I../../lib
|
||||
|
||||
include ../nosdk8266/Makefile
|
||||
|
||||
rf_data_gen : rf_data_gen.c
|
||||
gcc -g -Og -o $@ $^ -lm -DMAIN_MHZ=$(MAIN_MHZ)
|
||||
|
||||
samples.h : rf_data_gen
|
||||
./rf_data_gen
|
||||
|
||||
#chirpbuff.dat.flash : chirpbuff.dat
|
||||
# $(ESPUTIL) -b 115200 flash 0x20000 chirpbuff.dat
|
||||
|
||||
cleanall : clean
|
||||
rm -rf rf_data_gen samples.h
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# ESP8266 / ESP8285 310 MHz Transmitter
|
||||
|
||||
Transmits a 310 (or configurable) OOK pulse coded signal out the RX pin on the ESP8266/ESP8286.
|
||||
|
||||
You can also test it with an SDR and define
|
||||
|
||||
```c
|
||||
#define CONTINUOUS_TONE
|
||||
```
|
||||
|
||||
Frequency / word length can be configured in `rf_data_gen.c`
|
||||
@@ -0,0 +1 @@
|
||||
117
|
||||
@@ -0,0 +1,294 @@
|
||||
/**
|
||||
|
||||
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.
|
||||
|
||||
**/
|
||||
|
||||
#include "esp8266_auxrom.h"
|
||||
#include "eagle_soc.h"
|
||||
#include "nosdk8266.h"
|
||||
#include "esp8266_rom.h"
|
||||
#include <string.h>
|
||||
#include "ets_sys.h"
|
||||
#include "pin_mux_register.h"
|
||||
#include "slc_register.h"
|
||||
#include "dmastuff.h"
|
||||
#include "samples.h"
|
||||
|
||||
//#define CONTINUOUS_TONE
|
||||
|
||||
// The speed at which bits are shifted out - this is done with trial and error. Try one speed
|
||||
// and figure out how it aligns to your target system. The units are too messy for me to be
|
||||
// troubled with thinking of.
|
||||
|
||||
#define BIT_RATE 245
|
||||
#define num_replays (( SAMPLE_RATE / (DMA_WORDS*NUMBITS) ) / BIT_RATE)
|
||||
|
||||
uint8_t output_buffer[] = {
|
||||
// OOK, map to time_limits_for_bits, 0 is short pulse, 1 is long pulse, 2 is no-signal.
|
||||
// You will need to manually use your 310MHz device and record the pulse timing
|
||||
// To fill out this array with thecorrect code for your opener.
|
||||
0, 1, 0, 0, 0, 1, 1, 2, 2, 2, 2, 1, 0, 1, 0, 1, 0, 0, 1, 1,
|
||||
};
|
||||
uint32_t time_limits_for_bits[3] = { num_replays/8, num_replays/2, 0 };
|
||||
uint32_t dummy[DMA_WORDS];
|
||||
|
||||
void testi2s_init();
|
||||
|
||||
//These contol the speed at which the bus comms.
|
||||
#define DMABUFFERDEPTH 3
|
||||
#define WS_I2S_BCK SPI_DIV //Can't be less than 1.
|
||||
#define WS_I2S_DIV 1
|
||||
#define call_delay_us(time) { asm volatile("mov.n a2, %0\n_call0 delay4clk" : : "r"(time * (MAIN_MHZ / 8)) : "a2" ); }
|
||||
|
||||
//I2S DMA buffer descriptors
|
||||
static struct sdio_queue i2sBufDescTX[DMABUFFERDEPTH] __attribute__((aligned(128)));;
|
||||
|
||||
volatile int output_buffer_place = 1000000;
|
||||
volatile int count_out_this_bit = 0;
|
||||
volatile int etx = 0;
|
||||
|
||||
void slc_isr(void * v) {
|
||||
|
||||
uint32_t * sendbuff = 0;
|
||||
|
||||
struct sdio_queue *finishedDesc;
|
||||
// slc_intr_status = READ_PERI_REG(SLC_INT_STATUS); -> We should check to make sure we are SLC_RX_EOF_INT_ST, but we are only getting one interrupt.
|
||||
|
||||
WRITE_PERI_REG(SLC_INT_CLR, 0xffffffff);
|
||||
finishedDesc=(struct sdio_queue*)READ_PERI_REG(SLC_RX_EOF_DES_ADDR);
|
||||
|
||||
#ifdef CONTINUOUS_TONE
|
||||
return;
|
||||
#endif
|
||||
|
||||
etx++;
|
||||
|
||||
if( output_buffer_place >= sizeof( output_buffer ) / sizeof( output_buffer[0] ) )
|
||||
{
|
||||
goto dump0;
|
||||
}
|
||||
|
||||
count_out_this_bit++;
|
||||
|
||||
if( count_out_this_bit >= num_replays )
|
||||
{
|
||||
count_out_this_bit = 0;
|
||||
output_buffer_place++;
|
||||
|
||||
if( output_buffer_place >= sizeof( output_buffer ) / sizeof( output_buffer[0] ) )
|
||||
{
|
||||
goto dump0;
|
||||
}
|
||||
}
|
||||
|
||||
int symbol = output_buffer[output_buffer_place];
|
||||
|
||||
if( count_out_this_bit < time_limits_for_bits[symbol] )
|
||||
{
|
||||
sendbuff = samples;
|
||||
}
|
||||
else
|
||||
{
|
||||
sendbuff = dummy;
|
||||
}
|
||||
|
||||
finishedDesc->buf_ptr = (uint32_t)sendbuff;
|
||||
finishedDesc->datalen = DMA_WORDS*4;
|
||||
|
||||
return;
|
||||
dump0:
|
||||
finishedDesc->buf_ptr = (uint32_t)dummy;
|
||||
finishedDesc->datalen = DMA_WORDS*4;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TESTSTRAP
|
||||
|
||||
void SPIRead( uint32_t pos, uint32_t * buff, int len )
|
||||
{
|
||||
memcpy( buff, (pos - 0x00020000) + (uint8_t*)chirpbuff, len );
|
||||
}
|
||||
|
||||
void nosdk8266_init()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void testi2s_init()
|
||||
{
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
//Initialize I2S subsystem for DMA circular buffer use
|
||||
void testi2s_init() {
|
||||
int x, y;
|
||||
//Bits are shifted out
|
||||
|
||||
//Initialize DMA buffer descriptors in such a way that they will form a circular
|
||||
//buffer.
|
||||
|
||||
for (x=0; x<DMABUFFERDEPTH; x++) {
|
||||
i2sBufDescTX[x].owner=1;
|
||||
i2sBufDescTX[x].eof=1; // Trigger interrupt on packet complete.
|
||||
i2sBufDescTX[x].sub_sof=0;
|
||||
i2sBufDescTX[x].datalen=DMA_WORDS*4;
|
||||
i2sBufDescTX[x].blocksize=4;
|
||||
#ifdef CONTINUOUS_TONE
|
||||
i2sBufDescTX[x].buf_ptr= ((uint32_t)samples);
|
||||
#else
|
||||
i2sBufDescTX[x].buf_ptr= ((uint32_t)dummy);
|
||||
#endif
|
||||
i2sBufDescTX[x].unused=0;
|
||||
i2sBufDescTX[x].next_link_ptr=(int)((x<(DMABUFFERDEPTH-1))?(&i2sBufDescTX[x+1]):(&i2sBufDescTX[0]));
|
||||
}
|
||||
|
||||
//Reset DMA )
|
||||
//SLC_TX_LOOP_TEST = IF this isn't set, SO will occasionally get unrecoverable errors when you underflow.
|
||||
//Originally this little tidbit was found at https://github.com/pvvx/esp8266web/blob/master/info/libs/bios/sip_slc.c
|
||||
//
|
||||
//I have not tried without SLC_AHBM_RST | SLC_AHBM_FIFO_RST. I just assume they are useful?
|
||||
SET_PERI_REG_MASK(SLC_CONF0, SLC_TX_LOOP_TEST |SLC_RXLINK_RST|SLC_TXLINK_RST|SLC_AHBM_RST | SLC_AHBM_FIFO_RST);
|
||||
CLEAR_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST|SLC_TXLINK_RST|SLC_AHBM_RST | SLC_AHBM_FIFO_RST);
|
||||
|
||||
//Clear DMA int flags
|
||||
SET_PERI_REG_MASK(SLC_INT_CLR, 0xffffffff);
|
||||
CLEAR_PERI_REG_MASK(SLC_INT_CLR, 0xffffffff);
|
||||
|
||||
//Enable and configure DMA
|
||||
CLEAR_PERI_REG_MASK(SLC_CONF0, (SLC_MODE<<SLC_MODE_S));
|
||||
SET_PERI_REG_MASK(SLC_CONF0,(1<<SLC_MODE_S));
|
||||
|
||||
// We have to do this, otherwise, when the end of a "RX" packet is hit, it will skip outputting a few random frames.
|
||||
SET_PERI_REG_MASK(SLC_RX_DSCR_CONF,SLC_INFOR_NO_REPLACE|SLC_TOKEN_NO_REPLACE);
|
||||
CLEAR_PERI_REG_MASK(SLC_RX_DSCR_CONF, SLC_RX_FILL_EN|SLC_RX_EOF_MODE | SLC_RX_FILL_MODE);
|
||||
|
||||
CLEAR_PERI_REG_MASK(SLC_RX_LINK,SLC_RXLINK_DESCADDR_MASK);
|
||||
SET_PERI_REG_MASK(SLC_RX_LINK, ((uint32)&i2sBufDescTX[0]) & SLC_RXLINK_DESCADDR_MASK);
|
||||
|
||||
//Attach the DMA interrupt
|
||||
ets_isr_attach(ETS_SLC_INUM, slc_isr, 0);
|
||||
WRITE_PERI_REG(SLC_INT_ENA, SLC_RX_EOF_INT_ENA ); // Not including SLC_RX_UDF_INT_ENA
|
||||
|
||||
//clear any interrupt flags that are set
|
||||
WRITE_PERI_REG(SLC_INT_CLR, 0xffffffff);
|
||||
///enable DMA intr in cpu
|
||||
ets_isr_unmask(1<<ETS_SLC_INUM);
|
||||
|
||||
//Start transmission
|
||||
SET_PERI_REG_MASK(SLC_RX_LINK, SLC_RXLINK_START);
|
||||
|
||||
|
||||
//Init pins to i2s functions
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_I2SO_DATA); // GPIO3
|
||||
// PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_I2SO_WS); // GPIO2
|
||||
// PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_I2SO_BCK); // GPIO15
|
||||
|
||||
//Enable clock to i2s subsystem
|
||||
i2c_writeReg_Mask_def(i2c_bbpll, i2c_bbpll_en_audio_clock_out, 1);
|
||||
|
||||
//Reset I2S subsystem
|
||||
CLEAR_PERI_REG_MASK(I2SCONF,I2S_I2S_RESET_MASK);
|
||||
SET_PERI_REG_MASK(I2SCONF,I2S_I2S_RESET_MASK);
|
||||
CLEAR_PERI_REG_MASK(I2SCONF,I2S_I2S_RESET_MASK);
|
||||
|
||||
CLEAR_PERI_REG_MASK(I2S_FIFO_CONF, I2S_I2S_DSCR_EN|(I2S_I2S_RX_FIFO_MOD<<I2S_I2S_RX_FIFO_MOD_S));
|
||||
SET_PERI_REG_MASK(I2S_FIFO_CONF, I2S_I2S_DSCR_EN);
|
||||
WRITE_PERI_REG(I2SRXEOF_NUM, DMA_WORDS*4);
|
||||
|
||||
CLEAR_PERI_REG_MASK(I2SCONF_CHAN, (I2S_RX_CHAN_MOD<<I2S_RX_CHAN_MOD_S));
|
||||
|
||||
CLEAR_PERI_REG_MASK(I2SCONF, I2S_TRANS_SLAVE_MOD|I2S_RECE_SLAVE_MOD|
|
||||
(I2S_BITS_MOD<<I2S_BITS_MOD_S)|
|
||||
(I2S_BCK_DIV_NUM <<I2S_BCK_DIV_NUM_S)|
|
||||
(I2S_CLKM_DIV_NUM<<I2S_CLKM_DIV_NUM_S));
|
||||
|
||||
SET_PERI_REG_MASK(I2SCONF, I2S_RIGHT_FIRST|I2S_MSB_RIGHT|
|
||||
I2S_RECE_MSB_SHIFT|I2S_TRANS_MSB_SHIFT|
|
||||
((WS_I2S_BCK&I2S_BCK_DIV_NUM )<<I2S_BCK_DIV_NUM_S)|
|
||||
((WS_I2S_DIV&I2S_CLKM_DIV_NUM)<<I2S_CLKM_DIV_NUM_S) );
|
||||
|
||||
//Start transmission
|
||||
SET_PERI_REG_MASK(I2SCONF,I2S_I2S_TX_START|I2S_I2S_RX_START);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
// We store the bit pattern at flash:0x20000, so we don't have to constantly
|
||||
// re-write it when working on code.
|
||||
memset( dummy, 0, sizeof( dummy ) );
|
||||
|
||||
int frame = 0;
|
||||
output_buffer_place = 1000000;
|
||||
count_out_this_bit = 0;
|
||||
etx = 0;
|
||||
|
||||
// Don't crank up clock speed til we're done with flash.
|
||||
nosdk8266_init();
|
||||
|
||||
testi2s_init();
|
||||
|
||||
#ifdef CONTINUOUS_TONE
|
||||
while(1);
|
||||
#endif
|
||||
|
||||
|
||||
while(1) {
|
||||
//12x this speed.
|
||||
frame++;
|
||||
|
||||
PIN_OUT_SET = _BV(2); //Turn GPIO2 light off.
|
||||
//call_delay_us(1000000);
|
||||
printf("ETX: %d %d %d %d ( %d / %d ) / %d \n", etx, output_buffer_place, count_out_this_bit, num_replays, SAMPLE_RATE, BIT_RATE, DMA_WORDS );
|
||||
PIN_OUT_CLEAR = _BV(2); //Turn GPIO2 light off.
|
||||
|
||||
output_buffer_place = 0;
|
||||
count_out_this_bit = 0;
|
||||
call_delay_us(5000000);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
|
||||
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.
|
||||
|
||||
**/
|
||||
|
||||
// This file is for generated a 310MHz CW Tone that lines up with itself so
|
||||
// It can be repeated many times in-phase.
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
const double rf_frequency = 310;
|
||||
//const double spread = 0.000001;
|
||||
const double spread = 0.0;
|
||||
|
||||
#define SPI_DIV 1
|
||||
|
||||
#if MAIN_MHZ == 80
|
||||
const double sample_rate = 1040.0/13.0/SPI_DIV;
|
||||
|
||||
#elif MAIN_MHZ == 115
|
||||
const double sample_rate = 1040.0/9.0/SPI_DIV;
|
||||
|
||||
#elif MAIN_MHZ == 52
|
||||
const double sample_rate = 1040.0/20.0/SPI_DIV;
|
||||
|
||||
#elif MAIN_MHZ == 173
|
||||
const double sample_rate = 1040.0/6.0/SPI_DIV;
|
||||
|
||||
#else
|
||||
#error Unknown Clock Rate
|
||||
#endif
|
||||
|
||||
#define MAX_WORDS_DMA 511
|
||||
#define NUMBITS 32
|
||||
|
||||
int main()
|
||||
{
|
||||
int i;
|
||||
FILE * fcba = fopen( "samples.h", "w" );
|
||||
double phase = 0;
|
||||
uint32_t samplect = 0;
|
||||
uint32_t words = 0;
|
||||
uint32_t sample_word = 0;
|
||||
int32_t best_words = -1;
|
||||
double best_phase = 1000;
|
||||
double current_frequency = rf_frequency;
|
||||
for( i = 0; i < MAX_WORDS_DMA*NUMBITS; i++ )
|
||||
{
|
||||
phase += 3.1415926 * 2 * current_frequency / sample_rate;
|
||||
current_frequency += spread;
|
||||
while( phase > 3.1415926 * 2.0 ) phase -= 3.1415926 * 2.0;
|
||||
samplect++;
|
||||
if( samplect == NUMBITS )
|
||||
{
|
||||
words++;
|
||||
printf( "Phase Delta at %d: %f\n", words, phase );
|
||||
if( words > 64 ) // Minimum number of words
|
||||
{
|
||||
double phasediff = ( phase > 3.1415926 ) ? (3.1415926*2.0 - phase) : phase;
|
||||
if( phasediff < best_phase )
|
||||
{
|
||||
best_phase = phasediff;
|
||||
best_words = words;
|
||||
}
|
||||
}
|
||||
samplect = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t num_words = best_words;
|
||||
|
||||
printf( "Selected %d words\n", num_words );
|
||||
samplect = 0;
|
||||
words = 0;
|
||||
sample_word = 0;
|
||||
phase = 0;
|
||||
current_frequency = rf_frequency;
|
||||
|
||||
fprintf( fcba, "uint32_t samples[%d] = { \n\t", num_words );
|
||||
for( i = 0; i < num_words*NUMBITS; i++ )
|
||||
{
|
||||
phase += 3.1415926 * 2 * current_frequency / sample_rate;
|
||||
while( phase > 3.1415926 * 2.0 ) phase -= 3.1415926 * 2.0;
|
||||
current_frequency += spread;
|
||||
|
||||
// This is the magic line - this is what decides if you are emitting a `1` bit or a `0` bit.
|
||||
int bit = sin( phase ) > 0.0; // HINT: if you want to mix multiple signals, add a DC offset here.
|
||||
sample_word |= !!bit;
|
||||
samplect++;
|
||||
if( samplect == NUMBITS )
|
||||
{
|
||||
#ifdef USE_16_BITS
|
||||
fprintf( fcba, "0x%04x,%s", sample_word, ((words & 0xf) != 0xf)?" ":"\n\t" );
|
||||
#else
|
||||
fprintf( fcba, "0x%08x,%s", sample_word, ((words & 0xf) != 0xf)?" ":"\n\t" );
|
||||
#endif
|
||||
//fwrite( &sample_word, 1, NUMBITS/8, fd );
|
||||
words++;
|
||||
sample_word = 0;
|
||||
samplect = 0;
|
||||
}
|
||||
sample_word <<= 1;
|
||||
}
|
||||
fprintf( fcba, "};\n" );
|
||||
fprintf( fcba, "#define DMA_WORDS %d\n", num_words );
|
||||
fprintf( fcba, "#define SPI_DIV %d\n", SPI_DIV );
|
||||
fprintf( fcba, "#define NUMBITS %d\n", NUMBITS );
|
||||
fprintf( fcba, "#define SAMPLE_RATE %d\n", (int)(sample_rate*1000000) );
|
||||
}
|
||||
|
||||
Submodule
+1
Submodule esp8266/nosdk8266 added at c1628f15ee
Reference in New Issue
Block a user