├── ardop1ofdm ├── SerialIntefaceSpec.txt ├── i2cDisplay.c ├── TCPHostInterface.c ├── SerialIntefaceSpec.pdf ├── Version.h ├── config.doc ├── Makefile ├── MbedSerial.c ├── LCM1602-IIC.h ├── crcgen.c ├── pttio.h ├── soundio.h ├── kisspkt.h ├── audioio.h ├── galois.c ├── LCM1602-IIC.c ├── ecc.h ├── rs.doc ├── DACout.c ├── getopt.h ├── modem.h ├── pktARDOP.c ├── rs.c ├── FFT.c ├── LinSerial.c ├── UZ7HOFEC.c ├── NucleoSound.c ├── berlekamp.c ├── STM32main.cpp ├── SerialIntefaceSpec.html ├── Nucleo_i2c.c └── KISSModule.c ├── ardop2ofdm ├── SerialIntefaceSpec.txt ├── i2cDisplay.c ├── TCPHostInterface.c ├── SerialIntefaceSpec.pdf ├── Version.h ├── Makefile ├── kisspkt.h ├── ARDOPOFDM.txt ├── galois.c ├── ecc.h ├── pktARDOP.c ├── rs.c ├── FFT.c ├── LinSerial.c ├── berlekamp.c ├── SerialIntefaceSpec.html └── KISSModule.c ├── ardop_gui ├── ARDOP_GUI.qrc ├── main.cpp ├── ARDOP_GUI.pro ├── ardop_gui.h ├── TabDialog.h └── TabDialog.cpp ├── README.md ├── initscripts └── ardop.service └── .gitignore /ardop1ofdm/SerialIntefaceSpec.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ardop2ofdm/SerialIntefaceSpec.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ardop1ofdm/i2cDisplay.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalHERMES/ardopc/master/ardop1ofdm/i2cDisplay.c -------------------------------------------------------------------------------- /ardop2ofdm/i2cDisplay.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalHERMES/ardopc/master/ardop2ofdm/i2cDisplay.c -------------------------------------------------------------------------------- /ardop_gui/ARDOP_GUI.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /ardop1ofdm/TCPHostInterface.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalHERMES/ardopc/master/ardop1ofdm/TCPHostInterface.c -------------------------------------------------------------------------------- /ardop2ofdm/TCPHostInterface.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalHERMES/ardopc/master/ardop2ofdm/TCPHostInterface.c -------------------------------------------------------------------------------- /ardop1ofdm/SerialIntefaceSpec.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalHERMES/ardopc/master/ardop1ofdm/SerialIntefaceSpec.pdf -------------------------------------------------------------------------------- /ardop2ofdm/SerialIntefaceSpec.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalHERMES/ardopc/master/ardop2ofdm/SerialIntefaceSpec.pdf -------------------------------------------------------------------------------- /ardop1ofdm/Version.h: -------------------------------------------------------------------------------- 1 | 2 | const char ProductName[] = "ARDOP TNC"; 3 | const char ProductVersion[] = "1.0.4.1s-OFDMBPQ"; 4 | 5 | 6 | // 4.1s (Sept 2021) 7 | // Add GUI Support 8 | // Improve GUI Support 9 | // Add L/R soundcard and LOGDIR Options 10 | // Add EXTRADELAY parameter 11 | // Add CM108 PTT 12 | 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ardopc 2 | ARDOP (Amateur Radio Digital Open Protocol) TNC and SDR modem implementation by John Wiseman (GM8BPQ). Unofficial repository. 3 | 4 | Please visit the official documentation: 5 | http://www.cantab.net/users/john.wiseman/Downloads/Beta/ 6 | 7 | Source code fetched on 18 of June of 2020 from: 8 | http://www.cantab.net/users/john.wiseman/Downloads/Beta/TeensyProjects.zip 9 | -------------------------------------------------------------------------------- /ardop_gui/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ardop_gui.h" 2 | #include 3 | 4 | extern char Host[]; 5 | extern char Port[]; 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | if (argc > 2) 10 | { 11 | strcpy(Host, argv[1]); 12 | strcpy(Port, argv[2]); 13 | } 14 | 15 | QApplication a(argc, argv); 16 | ARDOP_GUI w; 17 | w.show(); 18 | 19 | return a.exec(); 20 | } 21 | -------------------------------------------------------------------------------- /initscripts/ardop.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=ARDOP daemon 3 | 4 | [Service] 5 | Type=simple 6 | ExecStart=/usr/bin/ardop 8515 -c /dev/ttyUSB0 ARDOP ARDOP -k FEFE88E01C0001FD -u FEFE88E01C0000FD 7 | ExecStop=/usr/bin/killall -s QUIT ardop 8 | IgnoreSIGPIPE=no 9 | #StandardOutput=null 10 | #StandardError=null 11 | StandardOutput=syslog 12 | StandardError=syslog 13 | Nice=-11 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /ardop2ofdm/Version.h: -------------------------------------------------------------------------------- 1 | 2 | const char ProductName[] = "ARDOP TNC"; 3 | const char ProductVersion[] = "2.0.3.40-BPQ-OFDM"; 4 | 5 | // 3.32 Fix tuning range 6 | // 3.33 Add GUI Support 7 | // 3.34 Improve GUI Support 8 | // Add L/R soundcard and LOGDIR Options 9 | // 3.35 Improvements to ARQ timing 10 | // 3.36 Add short (~2Sec) 4PSK mode for sending < 120 bytes of data 11 | // 3.37 Fix switching back from more robust mode if data outstanding 12 | // 3.38 Temporary disable Short frame sending stuff 13 | // 3.39 Fix shift error in 38 14 | // 3.40 Add EXTRADELAY parameter 15 | -------------------------------------------------------------------------------- /ardop1ofdm/config.doc: -------------------------------------------------------------------------------- 1 | The basic coding parameters are defined using 2 | macros, and an executable can be made by compiling using macro 3 | definitions defining the values of the following names in the file 4 | "ecc.h": 5 | 6 | The important compile time parameter is the number of parity bytes, 7 | specified by the #define NPAR. 8 | 9 | The library is shipped with 10 | 11 | #define NPAR 4 12 | 13 | The error-correction routines are polynomial in the number of 14 | parity bytes, so try to keep NPAR small for high performance. 15 | 16 | Remember, the sum of the message length (in bytes) plus parity bytes 17 | must be less than or equal to 255. 18 | 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /ardop1ofdm/Makefile: -------------------------------------------------------------------------------- 1 | # ARDOPC Makefile 2 | PREFIX=/usr 3 | OBJS = ofdm.o LinSerial.o KISSModule.o pktARDOP.o pktSession.o BusyDetect.o i2cDisplay.o ALSASound.o ARDOPC.o ardopSampleArrays.o ARQ.o FFT.o FEC.o HostInterface.o Modulate.o rs.o berlekamp.o galois.o SoundInput.o TCPHostInterface.o SCSHostInterface.o 4 | 5 | # Configuration: 6 | CFLAGS = -DLINBPQ -MMD -g 7 | CC = gcc 8 | 9 | all: ardopc 10 | 11 | ardopc: $(OBJS) 12 | gcc $(OBJS) -lrt -lm -lpthread -lasound -o ardop1ofdm 13 | 14 | install: ardop1ofdm 15 | install ardop1ofdm $(PREFIX)/bin 16 | ln -sf $(PREFIX)/bin/ardop1ofdm $(PREFIX)/bin/ardop 17 | # install ../initscripts/ardop.service /etc/systemd/system 18 | 19 | -include *.d 20 | 21 | clean : 22 | rm ardop1ofdm *.o 23 | -------------------------------------------------------------------------------- /ardop2ofdm/Makefile: -------------------------------------------------------------------------------- 1 | # ARDOPC Makefile 2 | PREFIX=/usr 3 | OBJS = ofdm.o LinSerial.o KISSModule.o pktARDOP.o pktSession.o BusyDetect.o i2cDisplay.o ALSASound.o ARDOPC.o ardopSampleArrays.o ARQ.o FFT.o FEC.o HostInterface.o Modulate.o rs.o berlekamp.o galois.o SoundInput.o TCPHostInterface.o SCSHostInterface.o 4 | 5 | # Configuration: 6 | CFLAGS = -DLINBPQ -MMD -g 7 | CC = gcc 8 | 9 | all: ardopofdm 10 | 11 | ardopofdm: $(OBJS) 12 | gcc $(OBJS) -lrt -lm -lpthread -lasound -o ardopofdm 13 | 14 | install: ardopofdm 15 | install ardopofdm $(PREFIX)/bin 16 | ln -sf $(PREFIX)/bin/ardopofdm $(PREFIX)/bin/ardop 17 | # install ../initscripts/ardop.service /etc/systemd/system 18 | 19 | -include *.d 20 | 21 | clean : 22 | rm -f ardopofdm $(OBJS) output.map *.d 23 | -------------------------------------------------------------------------------- /ardop1ofdm/MbedSerial.c: -------------------------------------------------------------------------------- 1 | // ARDOP TNC Serial Interface for Nucleo Board 2 | // 3 | 4 | #define TRUE 1 5 | #define FALSE 0 6 | 7 | 8 | void ProcessSCSPacket(unsigned char * rxbuffer, int Length); 9 | 10 | unsigned char RXBUFFER[300]; 11 | 12 | extern volatile int RXBPtr; 13 | 14 | int HostInit() 15 | { 16 | return TRUE; 17 | } 18 | 19 | void HostPoll() 20 | { 21 | if (RXBPtr) 22 | { 23 | RXBUFFER[RXBPtr] = 0; 24 | Debugprintf("Host RX %d %s", RXBPtr, RXBUFFER); 25 | ProcessSCSPacket(RXBUFFER, RXBPtr); 26 | Sleep(100); 27 | } 28 | } 29 | 30 | // Don't want to run anything in interrupt context, so just save rx chars to RXBUFFER 31 | 32 | void SerialSink(unsigned char c) 33 | { 34 | // if (RXBPtr < 300) 35 | // RXBUFFER[RXBPtr++] = c; 36 | } 37 | 38 | 39 | void PutString(unsigned char * Msg) 40 | { 41 | SerialSendData(Msg, strlen(Msg)); 42 | } 43 | 44 | int PutChar(unsigned char c) 45 | { 46 | SerialSendData(&c, 1); 47 | return 0; 48 | } 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /ardop_gui/ARDOP_GUI.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2018-11-18T10:39:57 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui 8 | QT += network 9 | 10 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 11 | 12 | TARGET = ARDOP_GUI 13 | TEMPLATE = app 14 | 15 | # The following define makes your compiler emit warnings if you use 16 | # any feature of Qt which as been marked as deprecated (the exact warnings 17 | # depend on your compiler). Please consult the documentation of the 18 | # deprecated API in order to know how to port your code away from it. 19 | DEFINES += QT_DEPRECATED_WARNINGS 20 | 21 | # You can also make your code fail to compile if you use deprecated APIs. 22 | # In order to do so, uncomment the following line. 23 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 24 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 25 | 26 | 27 | SOURCES += main.cpp\ 28 | ardop_gui.cpp \ 29 | TabDialog.cpp 30 | 31 | HEADERS += ardop_gui.h \ 32 | TabDialog.h 33 | 34 | FORMS += ardop_gui.ui 35 | -------------------------------------------------------------------------------- /ardop1ofdm/LCM1602-IIC.h: -------------------------------------------------------------------------------- 1 | // COMMANDOS 2 | #define LCD_CLEARDISPLAY 0x01 3 | #define LCD_RETURNHOME 0x02 4 | #define LCD_ENTRYMODESET 0x04 5 | #define LCD_DISPLAYCONTROL 0x08 6 | #define LCD_CURSORSHIFT 0x10 7 | #define LCD_FUNCTIONSET 0x20 8 | #define LCD_SETCGRAMADDR 0x40 9 | #define LCD_SETDDRAMADDR 0x80 10 | #define LCD_BACKLIGHT 0x08 11 | #define LCD_NOBACKLIGHT 0x00 12 | 13 | // FLAGS PARA EL MODO DE ENTRADA 14 | #define LCD_ENTRYRIGHT 0x00 15 | #define LCD_ENTRYLEFT 0x02 16 | #define LCD_ENTRYSHIFTINCREMENT 0x01 17 | #define LCD_ENTRYSHIFTDECREMENT 0x00 18 | 19 | // FLAGS DE DISPLAY CONTROL 20 | #define LCD_DISPLAYON 0x04 21 | #define LCD_DISPLAYOFF 0x00 22 | #define LCD_CURSORON 0x02 23 | #define LCD_CURSOROFF 0x00 24 | #define LCD_BLINKON 0x01 25 | #define LCD_BLINKOFF 0x00 26 | 27 | // FLAGS DE FUNCTION SET 28 | #define LCD_8BITMODE 0x10 29 | #define LCD_4BITMODE 0x00 30 | #define LCD_2LINE 0x08 31 | #define LCD_1LINE 0x00 32 | #define LCD_5x10DOTS 0x04 33 | #define LCD_5x8DOTS 0x00 34 | 35 | 36 | #define LCD_EN 0x04 // Enable bit 37 | #define LCD_RW 0x02 // Read/Write bit 38 | #define LCD_RS 0x01 // Register select bit 39 | 40 | void clear(int file); 41 | void home(int file); 42 | void locate(int file, int row, int col); 43 | void print(int file, const char *text); 44 | int initialize(const char *i2c_device, int addr); 45 | void finalize(int file); 46 | 47 | -------------------------------------------------------------------------------- /ardop_gui/ardop_gui.h: -------------------------------------------------------------------------------- 1 | #ifndef ARDOP_GUI_H 2 | #define ARDOP_GUI_H 3 | #include "QtNetwork/QUdpSocket" 4 | #include "QDialog" 5 | #include 6 | #include 7 | 8 | namespace Ui { 9 | class ARDOP_GUI; 10 | } 11 | 12 | class ARDOP_GUI : public QMainWindow 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | ARDOP_GUI(QWidget *parent = Q_NULLPTR); 18 | ~ARDOP_GUI(); 19 | 20 | private slots: 21 | void readPendingDatagrams(); 22 | void socketError(); 23 | void MyTimerSlot(); 24 | void rxTimerSlot(); 25 | void Configure(); 26 | void setWaterfall(); 27 | void setSpectrum(); 28 | void setDisabled(); 29 | void setSendID(); 30 | void setSendCWID(); 31 | void setSend2ToneTest(); 32 | 33 | private: 34 | Ui::ARDOP_GUI *ui; 35 | QImage *Constellation; 36 | QImage *Waterfall; 37 | QImage *RXLevel; 38 | QUdpSocket * udpSocket; 39 | QMenu *configMenu; 40 | QMenu *graphicsMenu; 41 | QMenu *sendMenu; 42 | QMenu *abortMenu; 43 | // QMenu *configMenu; 44 | QAction *actConfigure; 45 | QAction *actWaterfall; 46 | QAction *actSpectrum; 47 | QAction *actDisabled; 48 | QAction *actSendID; 49 | QAction *actTwoToneTest; 50 | QAction *actSendCWID; 51 | QDialog *Config; 52 | QLabel *Busy; 53 | QTimer *rxtimer; 54 | 55 | void RefreshLevel(unsigned int Level); 56 | void RefreshConstellation(unsigned char * Data, int Count); 57 | void RefreshWaterfall(unsigned char * Data, int Count); 58 | void RefreshSpectrum(unsigned char * Data); 59 | void SetLEDS(unsigned char * Data); 60 | 61 | }; 62 | 63 | #endif // ARDOP_GUI_H 64 | -------------------------------------------------------------------------------- /ardop1ofdm/crcgen.c: -------------------------------------------------------------------------------- 1 | /***************************** 2 | * Copyright Henry Minsky (hqm@alum.mit.edu) 1991-2009 3 | * 4 | * This software library is licensed under terms of the GNU GENERAL 5 | * PUBLIC LICENSE 6 | * 7 | * RSCODE is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * RSCODE is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with Rscode. If not, see . 19 | 20 | * Commercial licensing is available under a separate license, please 21 | * contact author for details. 22 | * 23 | * Source code is available at http://rscode.sourceforge.net 24 | * 25 | * CRC-CCITT generator simulator for byte wide data. 26 | * 27 | * 28 | * CRC-CCITT = x^16 + x^12 + x^5 + 1 29 | * 30 | * 31 | ******************************/ 32 | 33 | 34 | #include "ecc.h" 35 | 36 | BIT16 crchware(BIT16 data, BIT16 genpoly, BIT16 accum); 37 | 38 | /* Computes the CRC-CCITT checksum on array of byte data, length len 39 | */ 40 | BIT16 crc_ccitt(unsigned char *msg, int len) 41 | { 42 | int i; 43 | BIT16 acc = 0; 44 | 45 | for (i = 0; i < len; i++) { 46 | acc = crchware((BIT16) msg[i], (BIT16) 0x1021, acc); 47 | } 48 | 49 | return(acc); 50 | } 51 | 52 | /* models crc hardware (minor variation on polynomial division algorithm) */ 53 | BIT16 crchware(BIT16 data, BIT16 genpoly, BIT16 accum) 54 | { 55 | static BIT16 i; 56 | data <<= 8; 57 | for (i = 8; i > 0; i--) { 58 | if ((data ^ accum) & 0x8000) 59 | accum = ((accum << 1) ^ genpoly) & 0xFFFF; 60 | else 61 | accum = (accum<<1) & 0xFFFF; 62 | data = (data<<1) & 0xFFFF; 63 | } 64 | return (accum); 65 | } 66 | 67 | -------------------------------------------------------------------------------- /ardop1ofdm/pttio.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************/ 2 | 3 | /* 4 | * pttio.h -- Internal PTT input/output data structures and routines. 5 | * 6 | * Copyright (C) 2000, 2014 7 | * Thomas Sailer (sailer@ife.ee.ethz.ch) 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 | * 23 | */ 24 | 25 | /*****************************************************************************/ 26 | 27 | #ifndef _PTTIO_H 28 | #define _PTTIO_H 29 | 30 | /* ---------------------------------------------------------------------- */ 31 | 32 | #ifdef HAVE_CONFIG_H 33 | #include "config.h" 34 | #endif 35 | 36 | #ifdef WIN32 37 | #include 38 | #endif 39 | 40 | /* ---------------------------------------------------------------------- */ 41 | 42 | #ifdef WIN32 43 | 44 | struct pttio { 45 | HANDLE h; 46 | unsigned int ptt; 47 | unsigned int dcd; 48 | }; 49 | 50 | #else 51 | 52 | #ifdef HAVE_LIBHAMLIB 53 | #include 54 | #endif 55 | 56 | struct pttio { 57 | enum { noport, serport, parport, hamlibport, cm108, sysfsgpio } mode; 58 | unsigned int ptt; 59 | unsigned int dcd; 60 | unsigned int gpio; 61 | 62 | union { 63 | int fd; 64 | #ifdef HAVE_LIBHAMLIB 65 | RIG *rig_ptr; 66 | #endif 67 | } u; 68 | }; 69 | 70 | #endif 71 | 72 | /* ---------------------------------------------------------------------- */ 73 | 74 | extern struct modemparams pttparams[]; 75 | extern int pttinit(struct pttio *state, const char *params[]); 76 | extern void pttsetptt(struct pttio *state, int pttx); 77 | extern void pttsetdcd(struct pttio *state, int dcd); 78 | extern void pttrelease(struct pttio *state); 79 | 80 | /* ---------------------------------------------------------------------- */ 81 | #endif /* _PTTIO_H */ 82 | -------------------------------------------------------------------------------- /ardop1ofdm/soundio.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************/ 2 | 3 | /* 4 | * soundio.h -- Internal data structures. 5 | * 6 | * Copyright (C) 2000 7 | * Thomas Sailer (sailer@ife.ee.ethz.ch) 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 | * 23 | */ 24 | 25 | /*****************************************************************************/ 26 | 27 | #ifndef _SOUNDIO_H 28 | #define _SOUNDIO_H 29 | 30 | /* ---------------------------------------------------------------------- */ 31 | 32 | #include "modem.h" 33 | #include "kisspkt.h" 34 | #include "pttio.h" 35 | #include "audioio.h" 36 | 37 | #ifdef WIN32 38 | #include 39 | #else 40 | #define VOID void 41 | #endif 42 | #define pthread_t unsigned int 43 | 44 | 45 | /* ---------------------------------------------------------------------- */ 46 | 47 | struct state { 48 | struct modemchannel *channels; 49 | struct state *next; 50 | struct audioio *audioio; 51 | 52 | struct chacc chacc; 53 | 54 | struct pttio ptt; 55 | 56 | }; 57 | 58 | struct modemchannel 59 | { 60 | struct modemchannel *next; 61 | struct state *state; 62 | struct modulator *mod; 63 | struct demodulator *demod; 64 | void *modstate; 65 | void *demodstate; 66 | unsigned int rxbitrate; 67 | pthread_t rxthread; 68 | struct kisspkt pkt; 69 | }; 70 | 71 | extern struct state state; 72 | 73 | /* ---------------------------------------------------------------------- */ 74 | 75 | extern struct modemparams pktkissparams[]; 76 | extern void pktinit(struct modemchannel *chan); 77 | extern void pktrelease(struct modemchannel *chan); 78 | extern void pkttransmitloop(struct state *state); 79 | 80 | //extern int snprintpkt(char *buf, size_t sz, const u_int8_t *pkt, unsigned len); 81 | 82 | extern void logrelease(void); 83 | extern void loginit(unsigned int vl, unsigned int tosysl); 84 | 85 | extern struct modulator *modchain; 86 | extern struct demodulator *demodchain; 87 | 88 | /* ---------------------------------------------------------------------- */ 89 | #endif /* _SOUNDIO_H */ 90 | -------------------------------------------------------------------------------- /ardop1ofdm/kisspkt.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************/ 2 | 3 | /* 4 | * kisspkt.h -- Internal kisspkt data structures. 5 | * 6 | * Copyright (C) 2000 7 | * Thomas Sailer (sailer@ife.ee.ethz.ch) 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 | * 23 | */ 24 | 25 | /*****************************************************************************/ 26 | 27 | #ifndef _KISSPKT_H 28 | #define _KISSPKT_H 29 | 30 | /* ---------------------------------------------------------------------- */ 31 | 32 | #ifdef HAVE_CONFIG_H 33 | #include "config.h" 34 | #endif 35 | 36 | /* ---------------------------------------------------------------------- */ 37 | 38 | #define MAXFLEN 512U 39 | #define RXBUFFER_SIZE ((MAXFLEN*6U/5U)+8U) 40 | #define TXBUFFER_SIZE 4096U /* must be a power of 2 and >= MAXFLEN*6/5+8; NOTE: in words */ 41 | 42 | #define KISSINBUF_SIZE (2*MAXFLEN+8) 43 | 44 | #define IFNAMELEN 128 45 | 46 | /* ---------------------------------------------------------------------- */ 47 | 48 | struct chacc { 49 | unsigned int txdelay; 50 | unsigned int ppersist; 51 | unsigned int slottime; 52 | unsigned int fullduplex; 53 | unsigned int txtail; 54 | }; 55 | 56 | struct kisspkt { 57 | unsigned int dcd; 58 | unsigned int inhibittx; 59 | 60 | struct { 61 | unsigned rd, wr, txend; 62 | unsigned char buf[TXBUFFER_SIZE]; 63 | } htx; 64 | 65 | struct { 66 | unsigned int bitbuf, bitstream, numbits, state; 67 | unsigned char *bufptr; 68 | int bufcnt; 69 | unsigned char buf[RXBUFFER_SIZE]; 70 | } hrx; 71 | 72 | struct { 73 | int fd, fdmaster, ioerr; 74 | unsigned iframelen, ibufptr; 75 | char ifname[IFNAMELEN]; 76 | unsigned char ibuf[KISSINBUF_SIZE]; 77 | } kiss; 78 | 79 | struct { 80 | unsigned int kiss_in; 81 | unsigned int kiss_inerr; 82 | unsigned int kiss_out; 83 | unsigned int kiss_outerr; 84 | unsigned int pkt_in; 85 | unsigned int pkt_out; 86 | } stat; 87 | }; 88 | 89 | /* ---------------------------------------------------------------------- */ 90 | #endif /* _KISSPKT_H */ 91 | -------------------------------------------------------------------------------- /ardop2ofdm/kisspkt.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************/ 2 | 3 | /* 4 | * kisspkt.h -- Internal kisspkt data structures. 5 | * 6 | * Copyright (C) 2000 7 | * Thomas Sailer (sailer@ife.ee.ethz.ch) 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 | * 23 | */ 24 | 25 | /*****************************************************************************/ 26 | 27 | #ifndef _KISSPKT_H 28 | #define _KISSPKT_H 29 | 30 | /* ---------------------------------------------------------------------- */ 31 | 32 | #ifdef HAVE_CONFIG_H 33 | #include "config.h" 34 | #endif 35 | 36 | /* ---------------------------------------------------------------------- */ 37 | 38 | #define MAXFLEN 512U 39 | #define RXBUFFER_SIZE ((MAXFLEN*6U/5U)+8U) 40 | #define TXBUFFER_SIZE 4096U /* must be a power of 2 and >= MAXFLEN*6/5+8; NOTE: in words */ 41 | 42 | #define KISSINBUF_SIZE (2*MAXFLEN+8) 43 | 44 | #define IFNAMELEN 128 45 | 46 | /* ---------------------------------------------------------------------- */ 47 | 48 | struct chacc { 49 | unsigned int txdelay; 50 | unsigned int ppersist; 51 | unsigned int slottime; 52 | unsigned int fullduplex; 53 | unsigned int txtail; 54 | }; 55 | 56 | struct kisspkt { 57 | unsigned int dcd; 58 | unsigned int inhibittx; 59 | 60 | struct { 61 | unsigned rd, wr, txend; 62 | unsigned char buf[TXBUFFER_SIZE]; 63 | } htx; 64 | 65 | struct { 66 | unsigned int bitbuf, bitstream, numbits, state; 67 | unsigned char *bufptr; 68 | int bufcnt; 69 | unsigned char buf[RXBUFFER_SIZE]; 70 | } hrx; 71 | 72 | struct { 73 | int fd, fdmaster, ioerr; 74 | unsigned iframelen, ibufptr; 75 | char ifname[IFNAMELEN]; 76 | unsigned char ibuf[KISSINBUF_SIZE]; 77 | } kiss; 78 | 79 | struct { 80 | unsigned int kiss_in; 81 | unsigned int kiss_inerr; 82 | unsigned int kiss_out; 83 | unsigned int kiss_outerr; 84 | unsigned int pkt_in; 85 | unsigned int pkt_out; 86 | } stat; 87 | }; 88 | 89 | /* ---------------------------------------------------------------------- */ 90 | #endif /* _KISSPKT_H */ 91 | -------------------------------------------------------------------------------- /ardop2ofdm/ARDOPOFDM.txt: -------------------------------------------------------------------------------- 1 | ARDOPOFDM is an experimental extension to ARDOP2. The higher speed PSK and QAM modes of ARDOP2 are replaced with OFDM modes. There are two bandwidths, 500 and 2500 and 4 modes within each bandwidth (2PSK, 4PSK 8PSK and 16PSK or 16QAM). The code uses a modulation rate and carrier spacing of 55.555 Hz. The 500 mode uses 9 carriers and the 2500 mode 43 carriers. There isn't a 200 wide version. 2 | 3 | The code runs on Windows, Linux and my Teensy TNC. 4 | 5 | ARDOPOFDM has one new configuration parameter, ENABLEOFDM, with a default of TRUE. Apart from the new data frames it has two new CONREQ frames, OCONREQ500 and OCONREQ2500 and a new ACK, OFDMACK. If ENABLEOFDM is set it will send and accept the OCONREQ frames and the OFDM data frames. For compatibility with ARDOP2 stations if it receives a normal CONREQ frame it will disable the use of the OFDM data frames. If ENABLEOFDM is set to FALSE it will use normal CONREQ frames and reject OCONREQ, so it can connect to ARDOP2 stations. ARDOPOFDM acks each carrier separately, so only carriers that have failed to decode are repeated. If all carriers are ok a normal DataACK or DataACKHQ frame is sent, if not a slightly longer OFDMACK is sent which indicates which carriers need to be repeated. 6 | 7 | I haven't been able to evaluate it under a wide range of radio conditions, but initial testing looks promising. Under ideal conditions it is a bit over twice as fast as normal ARDOP (about 80% of the speed of VARA). Data frame length is a little under 5 seconds. Under ideal conditions performance in 2500 mode is 8 | 9 | 16OFDM 80 bytes/carrier, 3440 bytes per frame, approx 4600 BPS Net 10 | 8OFDM 60 bytes/carrier, 2580 bytes per frame, approx 3440 BPS Net 11 | 4OFDM 40 bytes/carrier, 1720 bytes per frame, approx 2300 BPS Net 12 | 2OFDM 19 bytes/carrier, 817 bytes per frame, approx 1100 BPS Net 13 | 14 | For Comparison 16QAM.2500.100 (10 Carriers) 15 | 16 | 120 bytes/carrier, 1200 bytes per frame, approx 2225 BPS Net 17 | 18 | As mentioned earlier this a experimental and modulation details and frame formats are likely to change as testing proceeds. It is really only suitable for people who a used to testing software. 19 | 20 | Software can be downloaded from 21 | 22 | http://www.cantab.net/users/john.wiseman/Downloads/Beta/ARDOPOFDM.exe 23 | http://www.cantab.net/users/john.wiseman/Downloads/Beta/ardopofdm 24 | http://www.cantab.net/users/john.wiseman/Downloads/Beta/piardopofdm 25 | http://www.cantab.net/users/john.wiseman/Downloads/Beta/TeensyProjects.zip 26 | 27 | 28 | The software has only been tested with BPQ32/LinBPQ and Winlink Express in PTC Emulation mode. You need to install the latest Beta BPQ32 or linbpq to use it. It may work with RMS Express in normal mode and Trimode, but this hasn't been tested and may result in slow running or data corruption due to changes in flow control thresholds. 29 | 30 | -------------------------------------------------------------------------------- /ardop1ofdm/audioio.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************/ 2 | 3 | /* 4 | * audioio.h -- Internal audioio data structures. 5 | * 6 | * Copyright (C) 2000 7 | * Thomas Sailer (sailer@ife.ee.ethz.ch) 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 | * 23 | */ 24 | 25 | /*****************************************************************************/ 26 | 27 | #ifndef _AUDIOIO_H 28 | #define _AUDIOIO_H 29 | 30 | /* ---------------------------------------------------------------------- */ 31 | 32 | #ifdef HAVE_CONFIG_H 33 | #include "config.h" 34 | #endif 35 | 36 | #include "modem.h" 37 | 38 | /* ---------------------------------------------------------------------- */ 39 | 40 | struct audioio { 41 | void (*release)(struct audioio *audioio); 42 | void (*terminateread)(struct audioio *audioio); 43 | void (*transmitstart)(struct audioio *audioio); 44 | void (*transmitstop)(struct audioio *audioio); 45 | void (*write)(struct audioio *audioio, const int16_t *samples, unsigned int nr); 46 | void (*read)(struct audioio *audioio, int16_t *samples, unsigned int nr, u_int16_t tim); 47 | u_int16_t (*curtime)(struct audioio *audioio); 48 | }; 49 | 50 | /* "private" audio IO functions */ 51 | extern struct modemparams ioparams_soundcard[]; 52 | extern struct modemparams ioparams_alsasoundcard[]; 53 | extern struct modemparams ioparams_filein[]; 54 | extern struct modemparams ioparams_sim[]; 55 | 56 | extern void ioinit_soundcard(void); 57 | extern void ioinit_alsasoundcard(void); 58 | extern void ioinit_filein(void); 59 | extern void ioinit_sim(void); 60 | 61 | #define IO_RDONLY 1 62 | #define IO_WRONLY 2 63 | #define IO_RDWR (IO_RDONLY|IO_WRONLY) 64 | 65 | extern struct audioio *ioopen_soundcard(unsigned int *samplerate, unsigned int flags, const char *params[]); 66 | extern struct audioio *ioopen_alsasoundcard(unsigned int *samplerate, unsigned int flags, const char *params[]); 67 | extern struct audioio *ioopen_filein(unsigned int *samplerate, unsigned int flags, const char *params[]); 68 | extern struct audioio *ioopen_sim(unsigned int *samplerate, unsigned int flags, const char *params[]); 69 | 70 | /* ---------------------------------------------------------------------- */ 71 | #endif /* _AUDIOIO_H */ 72 | -------------------------------------------------------------------------------- /ardop1ofdm/galois.c: -------------------------------------------------------------------------------- 1 | /***************************** 2 | * Copyright Henry Minsky (hqm@alum.mit.edu) 1991-2009 3 | * 4 | * This software library is licensed under terms of the GNU GENERAL 5 | * PUBLIC LICENSE 6 | * 7 | * RSCODE is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * RSCODE is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with Rscode. If not, see . 19 | 20 | * Commercial licensing is available under a separate license, please 21 | * contact author for details. 22 | * 23 | * Source code is available at http://rscode.sourceforge.net 24 | * 25 | * 26 | * Multiplication and Arithmetic on Galois Field GF(256) 27 | * 28 | * From Mee, Daniel, "Magnetic Recording, Volume III", Ch. 5 by Patel. 29 | * 30 | * 31 | ******************************/ 32 | 33 | 34 | #include 35 | #include 36 | #include "ecc.h" 37 | 38 | /* This is one of 14 irreducible polynomials 39 | * of degree 8 and cycle length 255. (Ch 5, pp. 275, Magnetic Recording) 40 | * The high order 1 bit is implicit */ 41 | /* x^8 + x^4 + x^3 + x^2 + 1 */ 42 | #define PPOLY 0x1D 43 | 44 | 45 | int gexp[512]; 46 | int glog[256]; 47 | 48 | 49 | static void init_exp_table (void); 50 | 51 | 52 | void 53 | init_galois_tables (void) 54 | { 55 | /* initialize the table of powers of alpha */ 56 | init_exp_table(); 57 | } 58 | 59 | 60 | static void 61 | init_exp_table (void) 62 | { 63 | int i, z; 64 | int pinit,p1,p2,p3,p4,p5,p6,p7,p8; 65 | 66 | pinit = p2 = p3 = p4 = p5 = p6 = p7 = p8 = 0; 67 | p1 = 1; 68 | 69 | gexp[0] = 1; 70 | gexp[255] = gexp[0]; 71 | glog[0] = 0; /* shouldn't log[0] be an error? */ 72 | 73 | // Private pp8() As Integer = {1, 0, 1, 1, 1, 0, 0, 0, 1} 'specify irreducible polynomial coeffts */ 74 | 75 | for (i = 1; i < 256; i++) { 76 | pinit = p8; 77 | p8 = p7; 78 | p7 = p6; 79 | p6 = p5; 80 | p5 = p4 ^ pinit; 81 | p4 = p3 ^ pinit; 82 | p3 = p2 ^ pinit; 83 | p2 = p1; 84 | p1 = pinit; 85 | gexp[i] = p1 + p2*2 + p3*4 + p4*8 + p5*16 + p6*32 + p7*64 + p8*128; 86 | gexp[i+255] = gexp[i]; 87 | } 88 | 89 | for (i = 1; i < 256; i++) { 90 | for (z = 0; z < 256; z++) { 91 | if (gexp[z] == i) { 92 | glog[i] = z; 93 | break; 94 | } 95 | } 96 | } 97 | } 98 | 99 | /* multiplication using logarithms */ 100 | int gmult(int a, int b) 101 | { 102 | int i,j; 103 | if (a==0 || b == 0) return (0); 104 | i = glog[a]; 105 | j = glog[b]; 106 | return (gexp[i+j]); 107 | } 108 | 109 | 110 | int ginv (int elt) 111 | { 112 | return (gexp[255-glog[elt]]); 113 | } 114 | 115 | -------------------------------------------------------------------------------- /ardop2ofdm/galois.c: -------------------------------------------------------------------------------- 1 | /***************************** 2 | * Copyright Henry Minsky (hqm@alum.mit.edu) 1991-2009 3 | * 4 | * This software library is licensed under terms of the GNU GENERAL 5 | * PUBLIC LICENSE 6 | * 7 | * RSCODE is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * RSCODE is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with Rscode. If not, see . 19 | 20 | * Commercial licensing is available under a separate license, please 21 | * contact author for details. 22 | * 23 | * Source code is available at http://rscode.sourceforge.net 24 | * 25 | * 26 | * Multiplication and Arithmetic on Galois Field GF(256) 27 | * 28 | * From Mee, Daniel, "Magnetic Recording, Volume III", Ch. 5 by Patel. 29 | * 30 | * 31 | ******************************/ 32 | 33 | 34 | #include 35 | #include 36 | #include "ecc.h" 37 | 38 | /* This is one of 14 irreducible polynomials 39 | * of degree 8 and cycle length 255. (Ch 5, pp. 275, Magnetic Recording) 40 | * The high order 1 bit is implicit */ 41 | /* x^8 + x^4 + x^3 + x^2 + 1 */ 42 | #define PPOLY 0x1D 43 | 44 | 45 | int gexp[512]; 46 | int glog[256]; 47 | 48 | 49 | static void init_exp_table (void); 50 | 51 | 52 | void 53 | init_galois_tables (void) 54 | { 55 | /* initialize the table of powers of alpha */ 56 | init_exp_table(); 57 | } 58 | 59 | 60 | static void 61 | init_exp_table (void) 62 | { 63 | int i, z; 64 | int pinit,p1,p2,p3,p4,p5,p6,p7,p8; 65 | 66 | pinit = p2 = p3 = p4 = p5 = p6 = p7 = p8 = 0; 67 | p1 = 1; 68 | 69 | gexp[0] = 1; 70 | gexp[255] = gexp[0]; 71 | glog[0] = 0; /* shouldn't log[0] be an error? */ 72 | 73 | // Private pp8() As Integer = {1, 0, 1, 1, 1, 0, 0, 0, 1} 'specify irreducible polynomial coeffts */ 74 | 75 | for (i = 1; i < 256; i++) { 76 | pinit = p8; 77 | p8 = p7; 78 | p7 = p6; 79 | p6 = p5; 80 | p5 = p4 ^ pinit; 81 | p4 = p3 ^ pinit; 82 | p3 = p2 ^ pinit; 83 | p2 = p1; 84 | p1 = pinit; 85 | gexp[i] = p1 + p2*2 + p3*4 + p4*8 + p5*16 + p6*32 + p7*64 + p8*128; 86 | gexp[i+255] = gexp[i]; 87 | } 88 | 89 | for (i = 1; i < 256; i++) { 90 | for (z = 0; z < 256; z++) { 91 | if (gexp[z] == i) { 92 | glog[i] = z; 93 | break; 94 | } 95 | } 96 | } 97 | } 98 | 99 | /* multiplication using logarithms */ 100 | int gmult(int a, int b) 101 | { 102 | int i,j; 103 | if (a==0 || b == 0) return (0); 104 | i = glog[a]; 105 | j = glog[b]; 106 | return (gexp[i+j]); 107 | } 108 | 109 | 110 | int ginv (int elt) 111 | { 112 | return (gexp[255-glog[elt]]); 113 | } 114 | 115 | -------------------------------------------------------------------------------- /ardop1ofdm/LCM1602-IIC.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "LCM1602-IIC.h" 12 | 13 | void expanderWrite(int file, char value) 14 | { 15 | char buffer = value | LCD_BACKLIGHT; 16 | //printf("EW = %x\r\n", buffer); 17 | if (write(file, &buffer, 1) != 1) 18 | printf("Error escribiendo en el dispositivo.\r\n"); 19 | } 20 | 21 | void pulseEnable(int file, char value) 22 | { 23 | expanderWrite(file, value | LCD_EN); 24 | usleep(1); 25 | 26 | expanderWrite(file, value & ~LCD_EN); 27 | usleep(50); 28 | } 29 | 30 | void write4bits(int file, char value) 31 | { 32 | //printf("\r\n"); 33 | //printf("W4B\r\n"); 34 | expanderWrite(file, value); 35 | pulseEnable(file, value); 36 | //printf("\r\n"); 37 | } 38 | 39 | void send(int file, char value, char mode) 40 | { 41 | //printf("\r\nSEND\r\n"); 42 | char h = value & 0xf0; 43 | char l = (value << 4) & 0xf0; 44 | write4bits(file, h | mode); 45 | write4bits(file, l | mode); 46 | } 47 | 48 | void command(int file, char value) 49 | { 50 | send(file, value, 0); 51 | } 52 | 53 | int initialize(const char *i2c_device, int addr) 54 | { 55 | // Se abre el fichero del dispositivo 56 | int file = 0; 57 | if ((file = open(i2c_device, O_RDWR)) < 0) { 58 | printf("No se pudo abrir el dispositivo i2c: %s\r\n", i2c_device); 59 | return -1; 60 | } 61 | 62 | if (ioctl(file, I2C_SLAVE, addr) != 0) { 63 | printf("No se ha podido seleccionar la dirección del esclavo\r\n"); 64 | return -1; 65 | } 66 | 67 | usleep(50000); 68 | expanderWrite(file, LCD_BACKLIGHT); 69 | usleep(1000000); 70 | 71 | // Se comienza en modo 4 bit, intentamos poner en modo 4 bit 72 | write4bits(file, 0x03 << 4); 73 | usleep(4500); 74 | write4bits(file, 0x30); 75 | usleep(4500); 76 | write4bits(file, 0x30); 77 | usleep(150); 78 | 79 | // Finalmente se pone el interface en 4 bit 80 | write4bits(file, 0x20); 81 | 82 | // Se configura el número de líneas 83 | command(file, LCD_FUNCTIONSET | LCD_2LINE); 84 | command(file, LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF); 85 | clear(file); 86 | 87 | // Se inicializa la dirección del texto por defecto 88 | command(file, LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT); 89 | 90 | // Cursor al inicio 91 | home(file); 92 | 93 | return file; 94 | } 95 | 96 | void finalize(int file) 97 | { 98 | close(file); 99 | } 100 | 101 | void clear(int file) 102 | { 103 | command(file, LCD_CLEARDISPLAY); 104 | usleep(2000); 105 | } 106 | 107 | void home(int file) 108 | { 109 | command(file, LCD_RETURNHOME); 110 | usleep(2000); 111 | } 112 | 113 | void locate(int file, int row, int col) 114 | { 115 | static int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; 116 | command(file, LCD_SETDDRAMADDR | ((col % 16) + row_offsets[row % 2])); 117 | } 118 | 119 | void locateCG(int file, int n) 120 | { 121 | command(file, LCD_SETCGRAMADDR + n); 122 | } 123 | 124 | 125 | void print(int file, const char *text) 126 | { 127 | int i = 0; 128 | int tlen = strlen(text); 129 | for (i = 0; i < tlen; i++) 130 | send(file, text[i], LCD_RS); 131 | } 132 | 133 | -------------------------------------------------------------------------------- /ardop_gui/TabDialog.h: -------------------------------------------------------------------------------- 1 | 2 | /**************************************************************************** 3 | ** 4 | ** Copyright (C) 2016 The Qt Company Ltd. 5 | ** Contact: https://www.qt.io/licensing/ 6 | ** 7 | ** This file is part of the examples of the Qt Toolkit. 8 | ** 9 | ** $QT_BEGIN_LICENSE:BSD$ 10 | ** Commercial License Usage 11 | ** Licensees holding valid commercial Qt licenses may use this file in 12 | ** accordance with the commercial license agreement provided with the 13 | ** Software or, alternatively, in accordance with the terms contained in 14 | ** a written agreement between you and The Qt Company. For licensing terms 15 | ** and conditions see https://www.qt.io/terms-conditions. For further 16 | ** information use the contact form at https://www.qt.io/contact-us. 17 | ** 18 | ** BSD License Usage 19 | ** Alternatively, you may use this file under the terms of the BSD license 20 | ** as follows: 21 | ** 22 | ** "Redistribution and use in source and binary forms, with or without 23 | ** modification, are permitted provided that the following conditions are 24 | ** met: 25 | ** * Redistributions of source code must retain the above copyright 26 | ** notice, this list of conditions and the following disclaimer. 27 | ** * Redistributions in binary form must reproduce the above copyright 28 | ** notice, this list of conditions and the following disclaimer in 29 | ** the documentation and/or other materials provided with the 30 | ** distribution. 31 | ** * Neither the name of The Qt Company Ltd nor the names of its 32 | ** contributors may be used to endorse or promote products derived 33 | ** from this software without specific prior written permission. 34 | ** 35 | ** 36 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 37 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 38 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 39 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 40 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 42 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 43 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 44 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 45 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 46 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 47 | ** 48 | ** $QT_END_LICENSE$ 49 | ** 50 | ****************************************************************************/ 51 | 52 | 53 | #ifndef TABDIALOG_H 54 | #define TABDIALOG_H 55 | 56 | #include 57 | 58 | class QDialogButtonBox; 59 | class QFileInfo; 60 | class QTabWidget; 61 | 62 | namespace Ui { 63 | class TabDialog; 64 | } 65 | 66 | class GeneralTab : public QWidget 67 | { 68 | Q_OBJECT 69 | 70 | public: 71 | explicit GeneralTab(QWidget *parent = 0); 72 | }; 73 | 74 | class TabDialog : public QDialog 75 | { 76 | Q_OBJECT 77 | 78 | public: 79 | explicit TabDialog(QWidget *parent = 0); 80 | ~TabDialog(); 81 | 82 | private slots: 83 | void myaccept(); 84 | 85 | private: 86 | // Ui::TabDialog *ui; 87 | QTabWidget *tabWidget; 88 | QDialogButtonBox *buttonBox; 89 | }; 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /ardop1ofdm/ecc.h: -------------------------------------------------------------------------------- 1 | /* Reed Solomon Coding for glyphs 2 | * Copyright Henry Minsky (hqm@alum.mit.edu) 1991-2009 3 | * 4 | * This software library is licensed under terms of the GNU GENERAL 5 | * PUBLIC LICENSE 6 | * 7 | * RSCODE is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * RSCODE is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with Rscode. If not, see . 19 | * 20 | * Source code is available at http://rscode.sourceforge.net 21 | * 22 | * Commercial licensing is available under a separate license, please 23 | * contact author for details. 24 | * 25 | */ 26 | 27 | /**************************************************************** 28 | 29 | Below is NPAR, the only compile-time parameter you should have to 30 | modify. 31 | 32 | It is the number of parity bytes which will be appended to 33 | your data to create a codeword. 34 | 35 | Note that the maximum codeword size is 255, so the 36 | sum of your message length plus parity should be less than 37 | or equal to this maximum limit. 38 | 39 | In practice, you will get slooow error correction and decoding 40 | if you use more than a reasonably small number of parity bytes. 41 | (say, 10 or 20) 42 | 43 | ****************************************************************/ 44 | 45 | #define MAXNPAR 64 // Sets size of static tables 46 | 47 | extern int NPAR; // Currently used number 48 | 49 | /****************************************************************/ 50 | 51 | 52 | 53 | 54 | #define TRUE 1 55 | #define FALSE 0 56 | 57 | typedef unsigned long BIT32; 58 | typedef unsigned short BIT16; 59 | 60 | /* **************************************************************** */ 61 | 62 | /* Maximum degree of various polynomials. */ 63 | #define MAXDEG (MAXNPAR*2) 64 | 65 | /*************************************/ 66 | /* Encoder parity bytes */ 67 | extern int pBytes[MAXDEG]; 68 | 69 | /* Decoder syndrome bytes */ 70 | extern int synBytes[MAXDEG]; 71 | 72 | /* print debugging info */ 73 | extern int DEBUG; 74 | 75 | /* Reed Solomon encode/decode routines */ 76 | void initialize_ecc (void); 77 | int check_syndrome (void); 78 | void decode_data (unsigned char data[], int nbytes); 79 | void encode_data (unsigned char msg[], int nbytes, unsigned char dst[]); 80 | 81 | /* CRC-CCITT checksum generator */ 82 | BIT16 crc_ccitt(unsigned char *msg, int len); 83 | 84 | /* galois arithmetic tables */ 85 | extern int gexp[]; 86 | extern int glog[]; 87 | 88 | void init_galois_tables (void); 89 | int ginv(int elt); 90 | int gmult(int a, int b); 91 | 92 | 93 | /* Error location routines */ 94 | int correct_errors_erasures (unsigned char codeword[], int csize,int nerasures, int erasures[]); 95 | 96 | /* polynomial arithmetic */ 97 | void add_polys(int dst[], int src[]) ; 98 | void scale_poly(int k, int poly[]); 99 | void mult_polys(int dst[], int p1[], int p2[]); 100 | 101 | void copy_poly(int dst[], int src[]); 102 | void zero_poly(int poly[]); 103 | -------------------------------------------------------------------------------- /ardop2ofdm/ecc.h: -------------------------------------------------------------------------------- 1 | /* Reed Solomon Coding for glyphs 2 | * Copyright Henry Minsky (hqm@alum.mit.edu) 1991-2009 3 | * 4 | * This software library is licensed under terms of the GNU GENERAL 5 | * PUBLIC LICENSE 6 | * 7 | * RSCODE is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * RSCODE is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with Rscode. If not, see . 19 | * 20 | * Source code is available at http://rscode.sourceforge.net 21 | * 22 | * Commercial licensing is available under a separate license, please 23 | * contact author for details. 24 | * 25 | */ 26 | 27 | /**************************************************************** 28 | 29 | Below is NPAR, the only compile-time parameter you should have to 30 | modify. 31 | 32 | It is the number of parity bytes which will be appended to 33 | your data to create a codeword. 34 | 35 | Note that the maximum codeword size is 255, so the 36 | sum of your message length plus parity should be less than 37 | or equal to this maximum limit. 38 | 39 | In practice, you will get slooow error correction and decoding 40 | if you use more than a reasonably small number of parity bytes. 41 | (say, 10 or 20) 42 | 43 | ****************************************************************/ 44 | 45 | #define MAXNPAR 64 // Sets size of static tables 46 | 47 | extern int NPAR; // Currently used number 48 | 49 | /****************************************************************/ 50 | 51 | 52 | 53 | 54 | #define TRUE 1 55 | #define FALSE 0 56 | 57 | typedef unsigned long BIT32; 58 | typedef unsigned short BIT16; 59 | 60 | /* **************************************************************** */ 61 | 62 | /* Maximum degree of various polynomials. */ 63 | #define MAXDEG (MAXNPAR*2) 64 | 65 | /*************************************/ 66 | /* Encoder parity bytes */ 67 | extern int pBytes[MAXDEG]; 68 | 69 | /* Decoder syndrome bytes */ 70 | extern int synBytes[MAXDEG]; 71 | 72 | /* print debugging info */ 73 | extern int DEBUG; 74 | 75 | /* Reed Solomon encode/decode routines */ 76 | void initialize_ecc (void); 77 | int check_syndrome (void); 78 | void decode_data (unsigned char data[], int nbytes); 79 | void encode_data (unsigned char msg[], int nbytes, unsigned char dst[]); 80 | 81 | /* CRC-CCITT checksum generator */ 82 | BIT16 crc_ccitt(unsigned char *msg, int len); 83 | 84 | /* galois arithmetic tables */ 85 | extern int gexp[]; 86 | extern int glog[]; 87 | 88 | void init_galois_tables (void); 89 | int ginv(int elt); 90 | int gmult(int a, int b); 91 | 92 | 93 | /* Error location routines */ 94 | int correct_errors_erasures (unsigned char codeword[], int csize,int nerasures, int erasures[]); 95 | 96 | /* polynomial arithmetic */ 97 | void add_polys(int dst[], int src[]) ; 98 | void scale_poly(int k, int poly[]); 99 | void mult_polys(int dst[], int p1[], int p2[]); 100 | 101 | void copy_poly(int dst[], int src[]); 102 | void zero_poly(int poly[]); 103 | -------------------------------------------------------------------------------- /ardop1ofdm/rs.doc: -------------------------------------------------------------------------------- 1 | 2 | 3 | Introduction to Reed Solomon Codes: 4 | 5 | Henry Minsky, Universal Access Inc. 6 | hqm@alum.mit.edu 7 | 8 | [For details see Cain, Clark, "Error-Correction Coding For Digital 9 | Communications", pp. 205.] The Reed-Solomon Code is an algebraic code 10 | belonging to the class of BCH (Bose-Chaudry-Hocquehen) multiple burst 11 | correcting cyclic codes. The Reed Solomon code operates on bytes of 12 | fixed length. 13 | 14 | Given m parity bytes, a Reed-Solomon code can correct up to m byte 15 | errors in known positions (erasures), or detect and correct up to m/2 16 | byte errors in unknown positions. 17 | 18 | This is an implementation of a Reed-Solomon code with 8 bit bytes, and 19 | a configurable number of parity bytes. The maximum sequence length 20 | (codeword) that can be generated is 255 bytes, including parity bytes. 21 | In practice, shorter sequences are used. 22 | 23 | ENCODING: The basic principle of encoding is to find the remainder of 24 | the message divided by a generator polynomial G(x). The encoder works 25 | by simulating a Linear Feedback Shift Register with degree equal to 26 | G(x), and feedback taps with the coefficents of the generating 27 | polynomial of the code. 28 | 29 | The rs.c file contains an algorithm to generate the encoder polynomial 30 | for any number of bytes of parity, configurable as the NPAR constant 31 | in the file ecc.h. 32 | 33 | For this RS code, G(x) = (x-a^1)(x-a^2)(x-a^3)(x-a^4)...(x-a^NPAR) 34 | where 'a' is a primitive element of the Galois Field GF(256) (== 2). 35 | 36 | DECODING 37 | 38 | The decoder generates four syndrome bytes, which will be all zero if 39 | the message has no errors. If there are errors, the location and value 40 | of the errors can be determined in a number of ways. 41 | 42 | Computing the syndromes is easily done as a sum of products, see pp. 43 | 179 [Rhee 89]. 44 | 45 | Fundamentally, the syndome bytes form four simultaneous equations 46 | which can be solved to find the error locations. Once error locations 47 | are known, the syndrome bytes can be used to find the value of the 48 | errors, and they can thus be corrected. 49 | 50 | A simplified solution for locating and correcting single errors is 51 | given in Cain and Clark, Ch. 5. 52 | 53 | The more general error-location algorithm is the Berlekamp-Massey 54 | algorithm, which will locate up to four errors, by iteratively solving 55 | for the error-locator polynomial. The Modified Berlekamp Massey 56 | algorithm takes as initial conditions any known suspicious bytes 57 | (erasure flags) which you may have (such as might be flagged by 58 | a laser demodulator, or deduced from a failure in a cross-interleaved 59 | block code row or column). 60 | 61 | Once the location of errors is known, error correction is done using 62 | the error-evaluator polynomial. 63 | 64 | APPLICATION IDEAS 65 | 66 | As an example application, this library could be used to implement the 67 | Compact Disc standard of 24 data bytes and 4 parity bytes. A RS code 68 | with 24 data bytes and 4 parity bytes is referred to as a (28,24) RS 69 | code. A (n, k) RS code is said to have efficiency k/n. This first 70 | (28,24) coding is called the C2 or level 2 encoding, because in a 71 | doubly encoded scheme, the codewords are decoded at the second 72 | decoding step. 73 | 74 | In following the approach used by Compact Disc digital audio, the 28 75 | byte C2 codewords are four way interleaved and then the interleaved 76 | data is encoded again with a (32,28) RS code. The is the C1 encoding 77 | stage. This produces what is known as a "product code", and has 78 | excellent error correction capability due to the imposition of 79 | two-dimensional structure on the parity checks. The interleave helps 80 | to insure against the case that a multibyte burst error wipes out more 81 | than two bytes in each codeword. The cross-correction capability of 82 | the product code can provide backup if in fact there are more than 2 83 | uncorrectable errors in a block. 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /ardop1ofdm/DACout.c: -------------------------------------------------------------------------------- 1 | #include "ARDOPC.h" 2 | 3 | //#include "stm32f4xx.h" 4 | #include "stm32f4xx_gpio.h" 5 | #include 6 | #include 7 | //#include 8 | #include 9 | #include 10 | 11 | extern unsigned short buffer[2][1200]; 12 | 13 | #define DAC_DHR12R1_ADDR 0x40007408 // DAC 12 Bit Left Justified 14 | #define DAC_DHR12L1_ADDR 0x40007410 // DAC 12 Bit Right Justified 15 | #define CNT_FREQ 90000000 // TIM6 clock (prescaled APB1) ?? 180/2 16 | #define TIM_PERIOD (CNT_FREQ/24000) // Generate DMS Request at this interval. 17 | 18 | static void TIM6_Config(void); 19 | static void DAC1_Config(void); 20 | 21 | // DMA 1 Stream 5 Channel 7 is hard wired to the DAC 22 | 23 | void StartDAC() 24 | { 25 | // Set up the DAC and start sending a frame under DMA 26 | GPIO_InitTypeDef gpio_A; 27 | 28 | // We don't need to do this each time, but I doubt if it costs much 29 | 30 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); 31 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); 32 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); 33 | 34 | gpio_A.GPIO_Pin = GPIO_Pin_4; 35 | gpio_A.GPIO_Mode = GPIO_Mode_AN; 36 | gpio_A.GPIO_PuPd = GPIO_PuPd_NOPULL; 37 | GPIO_Init(GPIOA, &gpio_A); 38 | 39 | DAC1_Config(); 40 | TIM6_Config(); 41 | } 42 | 43 | void stopDAC() 44 | { 45 | TIM_Cmd(TIM6, DISABLE); 46 | DMA_Cmd(DMA1_Stream5, DISABLE); 47 | DAC_Cmd(DAC_Channel_1, DISABLE); 48 | DAC_DMACmd(DAC_Channel_1, DISABLE); 49 | } 50 | 51 | static void TIM6_Config(void) 52 | { 53 | TIM_TimeBaseInitTypeDef TIM6_TimeBase; 54 | 55 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); 56 | 57 | TIM_TimeBaseStructInit(&TIM6_TimeBase); 58 | TIM6_TimeBase.TIM_Period = (uint16_t)TIM_PERIOD; 59 | TIM6_TimeBase.TIM_Prescaler = 0; 60 | TIM6_TimeBase.TIM_ClockDivision = 0; 61 | TIM6_TimeBase.TIM_CounterMode = TIM_CounterMode_Up; 62 | TIM_TimeBaseInit(TIM6, &TIM6_TimeBase); 63 | TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update); // So it triggers DMA 64 | 65 | TIM_Cmd(TIM6, ENABLE); 66 | } 67 | 68 | static void DAC1_Config(void) 69 | { 70 | DAC_InitTypeDef DAC_INIT; 71 | DMA_InitTypeDef DMA_INIT; 72 | 73 | DAC_INIT.DAC_Trigger = DAC_Trigger_T6_TRGO; 74 | DAC_INIT.DAC_WaveGeneration = DAC_WaveGeneration_None; 75 | DAC_INIT.DAC_OutputBuffer = DAC_OutputBuffer_Enable; 76 | DAC_Init(DAC_Channel_1, &DAC_INIT); 77 | 78 | DMA_DeInit(DMA1_Stream5); 79 | 80 | // enable double buffering .. one buffer gets sent while we are filling the other 81 | 82 | DMA_DoubleBufferModeConfig(DMA1_Stream5, (uint32_t)&buffer[1], DMA_Memory_0); 83 | DMA_DoubleBufferModeCmd(DMA1_Stream5, ENABLE); 84 | 85 | DMA_INIT.DMA_Channel = DMA_Channel_7; 86 | DMA_INIT.DMA_PeripheralBaseAddr = DAC_DHR12R1_ADDR; 87 | DMA_INIT.DMA_Memory0BaseAddr = (uint32_t)&buffer[0]; 88 | DMA_INIT.DMA_DIR = DMA_DIR_MemoryToPeripheral; 89 | DMA_INIT.DMA_BufferSize = 1200; 90 | DMA_INIT.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 91 | DMA_INIT.DMA_MemoryInc = DMA_MemoryInc_Enable; 92 | DMA_INIT.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; 93 | DMA_INIT.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; 94 | DMA_INIT.DMA_Mode = DMA_Mode_Circular; 95 | DMA_INIT.DMA_Priority = DMA_Priority_High; 96 | DMA_INIT.DMA_FIFOMode = DMA_FIFOMode_Disable; 97 | DMA_INIT.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; 98 | DMA_INIT.DMA_MemoryBurst = DMA_MemoryBurst_Single; 99 | DMA_INIT.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; 100 | DMA_Init(DMA1_Stream5, &DMA_INIT); 101 | 102 | DMA_Cmd(DMA1_Stream5, ENABLE); 103 | DAC_Cmd(DAC_Channel_1, ENABLE); 104 | DAC_DMACmd(DAC_Channel_1, ENABLE); 105 | } 106 | -------------------------------------------------------------------------------- /ardop1ofdm/getopt.h: -------------------------------------------------------------------------------- 1 | #ifndef __GETOPT_H__ 2 | /* 3 | * getopt.h 4 | * 5 | * $Id: getopt.h,v 1.4 2009/01/04 17:35:36 keithmarshall Exp $ 6 | * 7 | * Defines constants and function prototypes required to implement 8 | * the `getopt', `getopt_long' and `getopt_long_only' APIs. 9 | * 10 | * This file is part of the MinGW32 package set. 11 | * 12 | * Contributed by Keith Marshall 13 | * 14 | * 15 | * THIS SOFTWARE IS NOT COPYRIGHTED 16 | * 17 | * This source code is offered for use in the public domain. You may 18 | * use, modify or distribute it freely. 19 | * 20 | * This code is distributed in the hope that it will be useful but 21 | * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY 22 | * DISCLAIMED. This includes but is not limited to warranties of 23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 24 | * 25 | * $Revision: 1.4 $ 26 | * $Author: keithmarshall $ 27 | * $Date: 2009/01/04 17:35:36 $ 28 | * 29 | */ 30 | #define __GETOPT_H__ 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | extern int optind; /* index of first non-option in argv */ 37 | extern int optopt; /* single option character, as parsed */ 38 | extern int opterr; /* flag to enable built-in diagnostics... */ 39 | /* (user may set to zero, to suppress) */ 40 | 41 | extern char *optarg; /* pointer to argument of current option */ 42 | 43 | extern int getopt( int, char * const [], const char * ); 44 | 45 | #ifdef _BSD_SOURCE 46 | /* 47 | * BSD adds the non-standard `optreset' feature, for reinitialisation 48 | * of `getopt' parsing. We support this feature, for applications which 49 | * proclaim their BSD heritage, before including this header; however, 50 | * to maintain portability, developers are advised to avoid it. 51 | */ 52 | # define optreset __mingw_optreset 53 | 54 | extern int optreset; 55 | #endif 56 | #ifdef __cplusplus 57 | } 58 | #endif 59 | /* 60 | * POSIX requires the `getopt' API to be specified in `unistd.h'; 61 | * thus, `unistd.h' includes this header. However, we do not want 62 | * to expose the `getopt_long' or `getopt_long_only' APIs, when 63 | * included in this manner. Thus, close the standard __GETOPT_H__ 64 | * declarations block, and open an additional __GETOPT_LONG_H__ 65 | * specific block, only when *not* __UNISTD_H_SOURCED__, in which 66 | * to declare the extended API. 67 | */ 68 | #endif /* !defined(__GETOPT_H__) */ 69 | #if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) 70 | #define __GETOPT_LONG_H__ 71 | 72 | #ifdef __cplusplus 73 | extern "C" { 74 | #endif 75 | 76 | struct option /* specification for a long form option... */ 77 | { 78 | const char *name; /* option name, without leading hyphens */ 79 | int has_arg; /* does it take an argument? */ 80 | int *flag; /* where to save its status, or NULL */ 81 | int val; /* its associated status value */ 82 | }; 83 | 84 | enum /* permitted values for its `has_arg' field... */ 85 | { 86 | no_argument = 0, /* option never takes an argument */ 87 | required_argument, /* option always requires an argument */ 88 | optional_argument /* option may take an argument */ 89 | }; 90 | 91 | extern int getopt_long( int, char * const [], const char *, const struct option *, int * ); 92 | extern int getopt_long_only( int, char * const [], const char *, const struct option *, int * ); 93 | /* 94 | * Previous MinGW implementation had... 95 | */ 96 | #ifndef HAVE_DECL_GETOPT 97 | /* 98 | * ...for the long form API only; keep this for compatibility. 99 | */ 100 | # define HAVE_DECL_GETOPT 1 101 | #endif 102 | 103 | #ifdef __cplusplus 104 | } 105 | #endif 106 | 107 | #endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */ 108 | /* $RCSfile: getopt.h,v $Revision: 1.4 $: end of file */ -------------------------------------------------------------------------------- /ardop_gui/TabDialog.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the examples of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:BSD$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see https://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at https://www.qt.io/contact-us. 16 | ** 17 | ** BSD License Usage 18 | ** Alternatively, you may use this file under the terms of the BSD license 19 | ** as follows: 20 | ** 21 | ** "Redistribution and use in source and binary forms, with or without 22 | ** modification, are permitted provided that the following conditions are 23 | ** met: 24 | ** * Redistributions of source code must retain the above copyright 25 | ** notice, this list of conditions and the following disclaimer. 26 | ** * Redistributions in binary form must reproduce the above copyright 27 | ** notice, this list of conditions and the following disclaimer in 28 | ** the documentation and/or other materials provided with the 29 | ** distribution. 30 | ** * Neither the name of The Qt Company Ltd nor the names of its 31 | ** contributors may be used to endorse or promote products derived 32 | ** from this software without specific prior written permission. 33 | ** 34 | ** 35 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 36 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 37 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 38 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 39 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 42 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 43 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 44 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 45 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 46 | ** 47 | ** $QT_END_LICENSE$ 48 | ** 49 | ****************************************************************************/ 50 | 51 | 52 | #include 53 | #include "QSettings" 54 | 55 | #include "TabDialog.h" 56 | 57 | extern char Host[256]; 58 | extern char Port[16]; 59 | 60 | QLineEdit *hostEdit; 61 | QLineEdit *portEdit; 62 | 63 | //ARDOP_GUI::ARDOP_GUI(QWidget *parent) : QMainWindow(parent), ui(new Ui::ARDOP_GUI) 64 | 65 | TabDialog::TabDialog(QWidget *parent) : QDialog(parent) 66 | { 67 | tabWidget = new QTabWidget; 68 | tabWidget->addTab(new GeneralTab, tr("General")); 69 | 70 | buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); 71 | 72 | // connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); 73 | connect(buttonBox, SIGNAL(accepted()), this, SLOT(myaccept())); 74 | connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); 75 | 76 | QVBoxLayout *mainLayout = new QVBoxLayout; 77 | mainLayout->addWidget(tabWidget); 78 | mainLayout->addWidget(buttonBox); 79 | setLayout(mainLayout); 80 | 81 | setWindowTitle(tr("ARDOP_GUI onfiguration")); 82 | } 83 | 84 | GeneralTab::GeneralTab(QWidget *parent) 85 | : QWidget(parent) 86 | { 87 | QLabel *hostLabel = new QLabel(tr("Host Name:")); 88 | hostEdit = new QLineEdit(Host); 89 | QLabel *portLabel = new QLabel(tr("Port:")); 90 | portEdit = new QLineEdit(Port); 91 | QVBoxLayout *mainLayout = new QVBoxLayout; 92 | mainLayout->addWidget(hostLabel); 93 | mainLayout->addWidget(hostEdit); 94 | mainLayout->addWidget(portLabel); 95 | mainLayout->addWidget(portEdit); 96 | mainLayout->addStretch(1); 97 | setLayout(mainLayout); 98 | } 99 | 100 | void TabDialog::myaccept() 101 | { 102 | QString val = hostEdit->text(); 103 | QByteArray qb = val.toLatin1(); 104 | char * ptr = qb.data(); 105 | strcpy(Host, ptr); 106 | 107 | val = portEdit->text(); 108 | qb = val.toLatin1(); 109 | ptr = qb.data(); 110 | strcpy(Port, ptr); 111 | 112 | QSettings settings("G8BPQ", "ARDOP_GUI"); 113 | settings.setValue("Host", Host); 114 | settings.setValue("Port", Port); 115 | 116 | TabDialog::accept(); 117 | 118 | QMessageBox::information(this, tr("ARDOP_GUI"), tr("You need to restart to apply changes"), QMessageBox::Ok); 119 | } 120 | 121 | TabDialog::~TabDialog() 122 | { 123 | } 124 | -------------------------------------------------------------------------------- /ardop1ofdm/modem.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************/ 2 | 3 | /* 4 | * modem.h -- Defines for the modem. 5 | * 6 | * Copyright (C) 1999-2015 Thomas Sailer (sailer@ife.ee.ethz.ch) 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | * 22 | * Please note that the GPL allows you to use the driver, NOT the radio. 23 | * In order to use the radio, you need a license from the communications 24 | * authority of your country. 25 | * 26 | */ 27 | 28 | /*****************************************************************************/ 29 | 30 | #ifndef _MODEM_H 31 | #define _MODEM_H 32 | 33 | /* ---------------------------------------------------------------------- */ 34 | 35 | #ifdef HAVE_CONFIG_H 36 | #include "config.h" 37 | #endif 38 | 39 | #include 40 | #include 41 | 42 | #define int8_t char 43 | #define u_int8_t unsigned char 44 | 45 | #define int16_t short 46 | #define u_int16_t unsigned short 47 | 48 | #define int32_t int 49 | #define u_int32_t unsigned int 50 | 51 | #define only_inline 52 | #define only_inline 53 | 54 | #define alloca _alloca 55 | struct modemchannel; 56 | 57 | extern void audiowrite(struct modemchannel *chan, const int16_t *samples, unsigned int nr); 58 | extern void audioread(struct modemchannel *chan, int16_t *samples, unsigned int nr, u_int16_t tim); 59 | extern u_int16_t audiocurtime(struct modemchannel *chan); 60 | 61 | extern int pktget(struct modemchannel *chan, unsigned char *data, unsigned int len); 62 | extern void pktput(struct modemchannel *chan, const unsigned char *data, unsigned int len); 63 | extern void pktsetdcd(struct modemchannel *chan, int dcd); 64 | 65 | extern void p3dreceive(struct modemchannel *chan, const unsigned char *pkt, u_int16_t crc); 66 | extern void p3drxstate(struct modemchannel *chan, unsigned int synced, unsigned int carrierfreq); 67 | 68 | #define MLOG_FATAL 0 69 | #define MLOG_ERROR 1 70 | #define MLOG_WARNING 2 71 | #define MLOG_NOTICE 3 72 | #define MLOG_INFO 4 73 | #define MLOG_DEBUG 5 74 | 75 | extern void logvprintf(unsigned int level, const char *fmt, va_list args); 76 | extern void logprintf(unsigned int level, const char *fmt, ...); 77 | extern void logerr(unsigned int level, const char *st); 78 | extern unsigned int log_verblevel; 79 | void WriteDebugLog(int LogLevel, const char * format, ...); 80 | void SampleSink(short Sample); 81 | 82 | #define MODEMPAR_STRING 0 83 | #define MODEMPAR_COMBO 1 84 | #define MODEMPAR_NUMERIC 2 85 | #define MODEMPAR_CHECKBUTTON 3 86 | 87 | struct modemparams { 88 | const char *name; 89 | const char *label; 90 | const char *tooltip; 91 | const char *dflt; 92 | unsigned int type; 93 | union { 94 | struct { 95 | float min; 96 | float max; 97 | float step; 98 | float pagestep; 99 | } n; 100 | struct { 101 | const char *combostr[8]; 102 | } c; 103 | } u; 104 | }; 105 | 106 | struct modulator { 107 | struct modulator *next; 108 | const char *name; 109 | const struct modemparams *params; 110 | void *(*config)(struct modemchannel *chan, unsigned int *samplerate, int P1, int P2, int P3); 111 | void (*init)(void *, unsigned int samplerate); 112 | void (*modulate)(void *, unsigned int txdelay); 113 | void (*free)(void *); 114 | }; 115 | 116 | struct demodulator { 117 | struct demodulator *next; 118 | const char *name; 119 | const struct modemparams *params; 120 | void *(*config)(struct modemchannel *chan, unsigned int *samplerate, int P1, int P2, int P3); 121 | void (*init)(void *, unsigned int samplerate, unsigned int *bitrate); 122 | void (*demodulate)(void *); 123 | void (*free)(void *); 124 | }; 125 | 126 | /* ---------------------------------------------------------------------- */ 127 | 128 | extern struct modulator afskmodulator; 129 | extern struct demodulator afskdemodulator; 130 | 131 | extern struct modulator fskmodulator; 132 | extern struct demodulator fskdemodulator; 133 | extern struct demodulator fskpspdemodulator; 134 | extern struct demodulator fskeqdemodulator; 135 | 136 | extern struct modulator pammodulator; 137 | extern struct demodulator pamdemodulator; 138 | 139 | extern struct modulator pskmodulator; 140 | extern struct demodulator pskdemodulator; 141 | 142 | extern struct modulator newqpskmodulator; 143 | extern struct demodulator newqpskdemodulator; 144 | 145 | extern struct modulator p3dmodulator; 146 | extern struct demodulator p3ddemodulator; 147 | 148 | /* ---------------------------------------------------------------------- */ 149 | #endif /* _MODEM_H */ 150 | -------------------------------------------------------------------------------- /ardop1ofdm/pktARDOP.c: -------------------------------------------------------------------------------- 1 | // 2 | // Code for Packet using ARDOP like frames. 3 | // 4 | // This Module handles frame level stuff, and can be used 5 | // with a KISS interface. Module pktSession inplements an 6 | // ax.25 like Level 2, with dynamic parameter updating 7 | // 8 | // This uses Special Variable Length frames 9 | 10 | // Packet has header of 6 bytes sent in 4FSK.500.100. 11 | // Header is 6 bits Type 10 Bits Len 2 bytes CRC 2 bytes RS 12 | // Once we have that we receive the rest of the packet in the 13 | // mode defined in the header. 14 | // Uses Frame Type 0xC0, symbolic name PktFrameHeader 15 | 16 | 17 | #ifdef WIN32 18 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 19 | #define _CRT_SECURE_NO_DEPRECATE 20 | #define _USE_32BIT_TIME_T 21 | 22 | #include 23 | #include 24 | #else 25 | #define HANDLE int 26 | #endif 27 | 28 | #include "ARDOPC.h" 29 | 30 | 31 | extern UCHAR KISSBUFFER[500]; // Long enough for stuffed KISS frame 32 | extern int KISSLength; 33 | 34 | 35 | VOID EncodePacket(UCHAR * Data, int Len); 36 | VOID AddTxByteDirect(UCHAR Byte); 37 | VOID AddTxByteStuffed(UCHAR Byte); 38 | unsigned short int compute_crc(unsigned char *buf,int len); 39 | void PacketStartTX(); 40 | BOOL GetNextKISSFrame(); 41 | VOID SendAckModeAck(); 42 | 43 | extern unsigned char bytEncodedBytes[4500]; // I think the biggest is 600 bd 768 + overhead 44 | extern int EncLen; 45 | 46 | extern UCHAR PacketMon[360]; 47 | extern int PacketMonMore; 48 | extern int PacketMonLength; 49 | 50 | 51 | int pktBandwidth = 4; 52 | int pktMaxBandwidth = 8; 53 | int pktMaxFrame = 4; 54 | int pktPacLen = 80; 55 | 56 | int pktMode = 0; 57 | int pktRXMode; // Currently receiving mode 58 | 59 | int pktDataLen; 60 | int pktRSLen; 61 | 62 | // Now use Mode number to encode type and bandwidth 63 | 64 | const char pktMod[16][12] = { 65 | "4PSK/200", 66 | "4FSK/500", "4PSK/500", "8PSK/500", "16QAM/500", 67 | "4FSK/1000", "4PSK/1000", "8PSK/1000", "16QAM/1000", 68 | "4FSK/2000", "4PSK/2000", "8PSK/2000", "16QAM/2000", 69 | }; 70 | 71 | // Note FSK modes, though identified as 200 500 or 1000 actually 72 | // occupy 500, 1000 or 2000 BW 73 | 74 | const int pktBW[16] = {200, 75 | 500, 500, 500, 500, 76 | 1000, 1000, 1000, 1000, 77 | 2000, 2000, 2000, 2000}; 78 | 79 | const int pktCarriers[16] = { 80 | 1, 81 | 1, 2, 2, 2, 82 | 2, 4, 4, 4, 83 | 4, 8, 8, 8}; 84 | 85 | const BOOL pktFSK[16] = {0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0}; 86 | 87 | int pktModeLen = 13; 88 | 89 | VOID PktARDOPEncode(UCHAR * Data, int Len) 90 | { 91 | unsigned char DataToSend[4]; 92 | int pktNumCar = pktCarriers[pktMode]; 93 | 94 | // Header now sent as 4FSK.500.100 95 | // 6 Bits Mode, 10 Bits Length 96 | 97 | // 2 Bytes Header 2 Bytes CRC 2 Bytes RS 98 | 99 | if (Len > 1023) 100 | return; 101 | 102 | DataToSend[0] = (pktMode << 2)|(Len >> 8); 103 | DataToSend[1] = Len & 0xff; 104 | 105 | // Calc Data and RS Length 106 | 107 | pktDataLen = (Len + (pktNumCar - 1))/pktNumCar; // Round up 108 | 109 | pktRSLen = pktDataLen >> 2; // Try 25% for now 110 | 111 | if (pktRSLen & 1) 112 | pktRSLen++; // Odd RS bytes no use 113 | 114 | if (pktRSLen < 4) 115 | pktRSLen = 4; // At least 4 116 | 117 | // Encode Header 118 | 119 | EncLen = EncodeFSKData(PktFrameHeader, DataToSend, 2, bytEncodedBytes); 120 | 121 | // Encode Data 122 | 123 | if (pktFSK[pktMode]) 124 | EncodeFSKData(PktFrameData, Data, Len, &bytEncodedBytes[EncLen]); 125 | else 126 | EncodePSKData(PktFrameData, Data, Len, &bytEncodedBytes[EncLen]); 127 | 128 | // Header is FSK 129 | 130 | Mod4FSKDataAndPlay(bytEncodedBytes, EncLen, intCalcLeader); // Modulate Data frame 131 | } 132 | 133 | // Called when link idle to see if any packet frames to send 134 | 135 | void PktARDOPStartTX() 136 | { 137 | if (GetNextKISSFrame() == FALSE) 138 | return; // nothing to send 139 | 140 | while (TRUE) // loop till we run out of packets 141 | { 142 | switch(KISSBUFFER[0]) 143 | { 144 | case 0: // Normal Data 145 | 146 | WriteDebugLog(LOGALERT, "Sending Packet Frame Len %d", KISSLength - 1); 147 | 148 | PktARDOPEncode(KISSBUFFER + 1, KISSLength - 1); 149 | 150 | // Trace it 151 | 152 | if (PacketMonLength == 0) // Ingore if one queued 153 | { 154 | PacketMon[0] = 0x80; // TX Flag 155 | memcpy(&PacketMon[1], &KISSBUFFER[1], KISSLength); 156 | 157 | PacketMonLength = KISSLength; 158 | } 159 | 160 | break; 161 | 162 | case 6: // HW Paramters. Set Mode and Bandwidth 163 | 164 | pktMode = KISSBUFFER[1]; 165 | break; 166 | 167 | case 12: 168 | 169 | // Ackmode frame. Return ACK Bytes (first 2) to host when TX complete 170 | 171 | WriteDebugLog(LOGALERT, "Sending Packet Frame Len %d", KISSLength - 3); 172 | PktARDOPEncode(KISSBUFFER + 3, KISSLength - 3); 173 | 174 | // Returns when Complete so can send ACK 175 | 176 | SendAckModeAck(); 177 | break; 178 | } 179 | 180 | // See if any more 181 | 182 | if (GetNextKISSFrame() == FALSE) 183 | break; // no more to send 184 | } 185 | } 186 | 187 | -------------------------------------------------------------------------------- /ardop2ofdm/pktARDOP.c: -------------------------------------------------------------------------------- 1 | // 2 | // Code for Packet using ARDOP like frames. 3 | // 4 | // This Module handles frame level stuff, and can be used 5 | // with a KISS interface. Module pktSession inplements an 6 | // ax.25 like Level 2, with dynamic parameter updating 7 | // 8 | // This uses Special Variable Length frames 9 | 10 | // Packet has header of 6 bytes sent in 4FSK.500.100. 11 | // Header is 6 bits Type 10 Bits Len 2 bytes CRC 2 bytes RS 12 | // Once we have that we receive the rest of the packet in the 13 | // mode defined in the header. 14 | // Uses Frame Type 0xC0, symbolic name PktFrameHeader 15 | 16 | 17 | #ifdef WIN32 18 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 19 | #define _CRT_SECURE_NO_DEPRECATE 20 | #define _USE_32BIT_TIME_T 21 | 22 | #include 23 | #include 24 | #else 25 | #define HANDLE int 26 | #endif 27 | 28 | #include "ARDOPC.h" 29 | 30 | 31 | extern UCHAR KISSBUFFER[500]; // Long enough for stuffed KISS frame 32 | extern int KISSLength; 33 | 34 | 35 | VOID EncodePacket(UCHAR * Data, int Len); 36 | VOID AddTxByteDirect(UCHAR Byte); 37 | VOID AddTxByteStuffed(UCHAR Byte); 38 | unsigned short int compute_crc(unsigned char *buf,int len); 39 | void PacketStartTX(); 40 | BOOL GetNextKISSFrame(); 41 | VOID SendAckModeAck(); 42 | 43 | extern unsigned char bytEncodedBytes[4500]; // I think the biggest is 600 bd 768 + overhead 44 | extern int EncLen; 45 | 46 | extern UCHAR PacketMon[360]; 47 | extern int PacketMonMore; 48 | extern int PacketMonLength; 49 | 50 | 51 | int pktBandwidth = 4; 52 | int pktMaxBandwidth = 8; 53 | int pktMaxFrame = 4; 54 | int pktPacLen = 80; 55 | 56 | int pktMode = 0; 57 | int pktRXMode; // Currently receiving mode 58 | 59 | int pktDataLen; 60 | int pktRSLen; 61 | 62 | // Now use Mode number to encode type and bandwidth 63 | 64 | const char pktMod[16][12] = { 65 | "4PSK/200", 66 | "4FSK/500", "4PSK/500", "8PSK/500", "16QAM/500", 67 | "4FSK/1000", "4PSK/1000", "8PSK/1000", "16QAM/1000", 68 | "4FSK/2000", "4PSK/2000", "8PSK/2000", "16QAM/2000", 69 | }; 70 | 71 | // Note FSK modes, though identified as 200 500 or 1000 actually 72 | // occupy 500, 1000 or 2000 BW 73 | 74 | const int pktBW[16] = {200, 75 | 500, 500, 500, 500, 76 | 1000, 1000, 1000, 1000, 77 | 2000, 2500, 2500, 2500}; 78 | 79 | const int pktCarriers[16] = { 80 | 1, 81 | 1, 2, 2, 2, 82 | 2, 4, 4, 4, 83 | 4, 10, 10, 10}; 84 | 85 | const BOOL pktFSK[16] = {0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0}; 86 | 87 | int pktModeLen = 13; 88 | 89 | VOID PktARDOPEncode(UCHAR * Data, int Len) 90 | { 91 | unsigned char DataToSend[4]; 92 | int pktNumCar = pktCarriers[pktMode]; 93 | 94 | // Header now sent as 4FSK.500.100 95 | // 6 Bits Mode, 10 Bits Length 96 | 97 | // 2 Bytes Header 2 Bytes CRC 2 Bytes RS 98 | 99 | if (Len > 1023) 100 | return; 101 | 102 | DataToSend[0] = (pktMode << 2)|(Len >> 8); 103 | DataToSend[1] = Len & 0xff; 104 | 105 | // Calc Data and RS Length 106 | 107 | pktDataLen = (Len + (pktNumCar - 1))/pktNumCar; // Round up 108 | 109 | pktRSLen = pktDataLen >> 2; // Try 25% for now 110 | 111 | if (pktRSLen & 1) 112 | pktRSLen++; // Odd RS bytes no use 113 | 114 | if (pktRSLen < 4) 115 | pktRSLen = 4; // At least 4 116 | 117 | // Encode Header 118 | 119 | EncLen = EncodeFSKData(PktFrameHeader, DataToSend, 2, bytEncodedBytes); 120 | 121 | // Encode Data 122 | 123 | if (pktFSK[pktMode]) 124 | EncodeFSKData(PktFrameData, Data, Len, &bytEncodedBytes[EncLen]); 125 | else 126 | EncodePSKData(PktFrameData, Data, Len, &bytEncodedBytes[EncLen]); 127 | 128 | // Header is FSK 129 | 130 | Mod4FSKDataAndPlay(bytEncodedBytes, EncLen, intCalcLeader); // Modulate Data frame 131 | } 132 | 133 | // Called when link idle to see if any packet frames to send 134 | 135 | void PktARDOPStartTX() 136 | { 137 | if (GetNextKISSFrame() == FALSE) 138 | return; // nothing to send 139 | 140 | while (TRUE) // loop till we run out of packets 141 | { 142 | switch(KISSBUFFER[0]) 143 | { 144 | case 0: // Normal Data 145 | 146 | WriteDebugLog(LOGALERT, "Sending Packet Frame Len %d", KISSLength - 1); 147 | 148 | PktARDOPEncode(KISSBUFFER + 1, KISSLength - 1); 149 | 150 | // Trace it 151 | 152 | if (PacketMonLength == 0) // Ingore if one queued 153 | { 154 | PacketMon[0] = 0x80; // TX Flag 155 | memcpy(&PacketMon[1], &KISSBUFFER[1], KISSLength); 156 | 157 | PacketMonLength = KISSLength; 158 | } 159 | 160 | break; 161 | 162 | case 6: // HW Paramters. Set Mode and Bandwidth 163 | 164 | pktMode = KISSBUFFER[1]; 165 | break; 166 | 167 | case 12: 168 | 169 | // Ackmode frame. Return ACK Bytes (first 2) to host when TX complete 170 | 171 | WriteDebugLog(LOGALERT, "Sending Packet Frame Len %d", KISSLength - 3); 172 | PktARDOPEncode(KISSBUFFER + 3, KISSLength - 3); 173 | 174 | // Returns when Complete so can send ACK 175 | 176 | SendAckModeAck(); 177 | break; 178 | } 179 | 180 | // See if any more 181 | 182 | if (GetNextKISSFrame() == FALSE) 183 | break; // no more to send 184 | } 185 | } 186 | 187 | -------------------------------------------------------------------------------- /ardop1ofdm/rs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Reed Solomon Encoder/Decoder 3 | * 4 | * Copyright Henry Minsky (hqm@alum.mit.edu) 1991-2009 5 | * 6 | * This software library is licensed under terms of the GNU GENERAL 7 | * PUBLIC LICENSE 8 | * 9 | * RSCODE is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * RSCODE is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with Rscode. If not, see . 21 | 22 | * Commercial licensing is available under a separate license, please 23 | * contact author for details. 24 | * 25 | * Source code is available at http://rscode.sourceforge.net 26 | */ 27 | 28 | #define LOGEMERGENCY 0 29 | #define LOGALERT 1 30 | #define LOGCRIT 2 31 | #define LOGERROR 3 32 | #define LOGWARNING 4 33 | #define LOGNOTICE 5 34 | #define LOGINFO 6 35 | #define LOGDEBUG 7 36 | 37 | 38 | #include 39 | #include 40 | #include 41 | #include "ecc.h" 42 | 43 | void WriteDebugLog(int Level, const char * format, ...); 44 | 45 | /* Encoder parity bytes */ 46 | int pBytes[MAXDEG]; 47 | 48 | /* Decoder syndrome bytes */ 49 | int synBytes[MAXDEG]; 50 | 51 | /* generator polynomial */ 52 | int genPoly[MAXDEG*2]; 53 | 54 | int DEBUG = FALSE; //RUE; 55 | 56 | static void 57 | compute_genpoly (int nbytes, int genpoly[]); 58 | 59 | /* Initialize lookup tables, polynomials, etc. */ 60 | void 61 | initialize_ecc () 62 | { 63 | /* Initialize the galois field arithmetic tables */ 64 | init_galois_tables(); 65 | 66 | /* Compute the encoder generator polynomial */ 67 | compute_genpoly(NPAR, genPoly); 68 | } 69 | 70 | void 71 | zero_fill_from (unsigned char buf[], int from, int to) 72 | { 73 | int i; 74 | for (i = from; i < to; i++) buf[i] = 0; 75 | } 76 | 77 | /* debugging routines */ 78 | void 79 | print_parity (void) 80 | { 81 | int i; 82 | WriteDebugLog(LOGDEBUG, "Parity Bytes: "); 83 | for (i = 0; i < NPAR; i++) 84 | WriteDebugLog(LOGDEBUG, "[%d]:%x, ",i,pBytes[i]); 85 | WriteDebugLog(LOGDEBUG, "\n"); 86 | } 87 | 88 | 89 | void 90 | print_syndrome (void) 91 | { 92 | int i; 93 | WriteDebugLog(LOGDEBUG, "Syndrome Bytes: "); 94 | for (i = 0; i < NPAR; i++) 95 | WriteDebugLog(LOGDEBUG, "[%d]:%x, ",i,synBytes[i]); 96 | WriteDebugLog(LOGDEBUG, "\n"); 97 | } 98 | 99 | 100 | /********************************************************** 101 | * Reed Solomon Decoder 102 | * 103 | * Computes the syndrome of a codeword. Puts the results 104 | * into the synBytes[] array. 105 | */ 106 | 107 | void 108 | decode_data(unsigned char data[], int nbytes) 109 | { 110 | int i, j, sum; 111 | for (j = 0; j < NPAR; j++) 112 | { 113 | sum = 0; 114 | for (i = 0; i < nbytes; i++) 115 | { 116 | sum = data[i] ^ gmult(gexp[j+1], sum); 117 | } 118 | 119 | synBytes[j] = sum; 120 | 121 | // WriteDebugLog(LOGDEBUG, "%d %d %d\r\n", i, synBytes[i], index_of[s[i]]); 122 | 123 | } 124 | } 125 | 126 | 127 | /* Check if the syndrome is zero */ 128 | int 129 | check_syndrome (void) 130 | { 131 | int i, nz = 0; 132 | for (i =0 ; i < NPAR; i++) { 133 | if (synBytes[i] != 0) { 134 | nz = 1; 135 | break; 136 | } 137 | } 138 | return nz; 139 | } 140 | 141 | 142 | void 143 | debug_check_syndrome (void) 144 | { 145 | int i; 146 | 147 | for (i = 0; i < 3; i++) { 148 | WriteDebugLog(LOGDEBUG, " inv log S[%d]/S[%d] = %d\n", i, i+1, 149 | glog[gmult(synBytes[i], ginv(synBytes[i+1]))]); 150 | } 151 | } 152 | 153 | 154 | /* Create a generator polynomial for an n byte RS code. 155 | * The coefficients are returned in the genPoly arg. 156 | * Make sure that the genPoly array which is passed in is 157 | * at least n+1 bytes long. 158 | */ 159 | 160 | static void 161 | compute_genpoly (int nbytes, int genpoly[]) 162 | { 163 | int i, tp[256], tp1[256]; 164 | 165 | /* multiply (x + a^n) for n = 1 to nbytes */ 166 | 167 | zero_poly(tp1); 168 | tp1[0] = 1; 169 | 170 | for (i = 1; i <= nbytes; i++) { 171 | zero_poly(tp); 172 | tp[0] = gexp[i]; /* set up x+a^n */ 173 | tp[1] = 1; 174 | 175 | mult_polys(genpoly, tp, tp1); 176 | copy_poly(tp1, genpoly); 177 | } 178 | } 179 | 180 | /* Simulate a LFSR with generator polynomial for n byte RS code. 181 | * Pass in a pointer to the data array, and amount of data. 182 | * 183 | * The parity bytes are deposited into pBytes[], and the whole message 184 | * and parity are copied to dest to make a codeword. 185 | * 186 | */ 187 | 188 | void 189 | encode_data (unsigned char msg[], int nbytes, unsigned char dst[]) 190 | { 191 | int i ,dbyte, j; 192 | unsigned char LFSR[MAXNPAR+1]; 193 | 194 | for(i=0; i < NPAR+1; i++) 195 | LFSR[i]=0; 196 | 197 | // for (i = 0; i < nbytes; i++) 198 | for (i = nbytes-1; i >= 0; i--) // Order reversed for compatibility wiyh Rick' Code 199 | { 200 | dbyte = msg[i] ^ LFSR[NPAR-1]; 201 | for (j = NPAR-1; j > 0; j--) 202 | { 203 | LFSR[j] = LFSR[j-1] ^ gmult(genPoly[j], dbyte); 204 | } 205 | LFSR[0] = gmult(genPoly[0], dbyte); 206 | } 207 | 208 | // return the parity bytes 209 | 210 | memcpy(dst, LFSR, NPAR); 211 | } 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /ardop2ofdm/rs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Reed Solomon Encoder/Decoder 3 | * 4 | * Copyright Henry Minsky (hqm@alum.mit.edu) 1991-2009 5 | * 6 | * This software library is licensed under terms of the GNU GENERAL 7 | * PUBLIC LICENSE 8 | * 9 | * RSCODE is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * RSCODE is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with Rscode. If not, see . 21 | 22 | * Commercial licensing is available under a separate license, please 23 | * contact author for details. 24 | * 25 | * Source code is available at http://rscode.sourceforge.net 26 | */ 27 | 28 | #define LOGEMERGENCY 0 29 | #define LOGALERT 1 30 | #define LOGCRIT 2 31 | #define LOGERROR 3 32 | #define LOGWARNING 4 33 | #define LOGNOTICE 5 34 | #define LOGINFO 6 35 | #define LOGDEBUG 7 36 | 37 | 38 | #include 39 | #include 40 | #include 41 | #include "ecc.h" 42 | 43 | void WriteDebugLog(int Level, const char * format, ...); 44 | 45 | /* Encoder parity bytes */ 46 | int pBytes[MAXDEG]; 47 | 48 | /* Decoder syndrome bytes */ 49 | int synBytes[MAXDEG]; 50 | 51 | /* generator polynomial */ 52 | int genPoly[MAXDEG*2]; 53 | 54 | int DEBUG = FALSE; //RUE; 55 | 56 | static void 57 | compute_genpoly (int nbytes, int genpoly[]); 58 | 59 | /* Initialize lookup tables, polynomials, etc. */ 60 | void 61 | initialize_ecc () 62 | { 63 | /* Initialize the galois field arithmetic tables */ 64 | init_galois_tables(); 65 | 66 | /* Compute the encoder generator polynomial */ 67 | compute_genpoly(NPAR, genPoly); 68 | } 69 | 70 | void 71 | zero_fill_from (unsigned char buf[], int from, int to) 72 | { 73 | int i; 74 | for (i = from; i < to; i++) buf[i] = 0; 75 | } 76 | 77 | /* debugging routines */ 78 | void 79 | print_parity (void) 80 | { 81 | int i; 82 | WriteDebugLog(LOGDEBUG, "Parity Bytes: "); 83 | for (i = 0; i < NPAR; i++) 84 | WriteDebugLog(LOGDEBUG, "[%d]:%x, ",i,pBytes[i]); 85 | WriteDebugLog(LOGDEBUG, "\n"); 86 | } 87 | 88 | 89 | void 90 | print_syndrome (void) 91 | { 92 | int i; 93 | WriteDebugLog(LOGDEBUG, "Syndrome Bytes: "); 94 | for (i = 0; i < NPAR; i++) 95 | WriteDebugLog(LOGDEBUG, "[%d]:%x, ",i,synBytes[i]); 96 | WriteDebugLog(LOGDEBUG, "\n"); 97 | } 98 | 99 | 100 | /********************************************************** 101 | * Reed Solomon Decoder 102 | * 103 | * Computes the syndrome of a codeword. Puts the results 104 | * into the synBytes[] array. 105 | */ 106 | 107 | void 108 | decode_data(unsigned char data[], int nbytes) 109 | { 110 | int i, j, sum; 111 | for (j = 0; j < NPAR; j++) 112 | { 113 | sum = 0; 114 | for (i = 0; i < nbytes; i++) 115 | { 116 | sum = data[i] ^ gmult(gexp[j+1], sum); 117 | } 118 | 119 | synBytes[j] = sum; 120 | 121 | // WriteDebugLog(LOGDEBUG, "%d %d %d\r\n", i, synBytes[i], index_of[s[i]]); 122 | 123 | } 124 | } 125 | 126 | 127 | /* Check if the syndrome is zero */ 128 | int 129 | check_syndrome (void) 130 | { 131 | int i, nz = 0; 132 | for (i =0 ; i < NPAR; i++) { 133 | if (synBytes[i] != 0) { 134 | nz = 1; 135 | break; 136 | } 137 | } 138 | return nz; 139 | } 140 | 141 | 142 | void 143 | debug_check_syndrome (void) 144 | { 145 | int i; 146 | 147 | for (i = 0; i < 3; i++) { 148 | WriteDebugLog(LOGDEBUG, " inv log S[%d]/S[%d] = %d\n", i, i+1, 149 | glog[gmult(synBytes[i], ginv(synBytes[i+1]))]); 150 | } 151 | } 152 | 153 | 154 | /* Create a generator polynomial for an n byte RS code. 155 | * The coefficients are returned in the genPoly arg. 156 | * Make sure that the genPoly array which is passed in is 157 | * at least n+1 bytes long. 158 | */ 159 | 160 | static void 161 | compute_genpoly (int nbytes, int genpoly[]) 162 | { 163 | int i, tp[256], tp1[256]; 164 | 165 | /* multiply (x + a^n) for n = 1 to nbytes */ 166 | 167 | zero_poly(tp1); 168 | tp1[0] = 1; 169 | 170 | for (i = 1; i <= nbytes; i++) { 171 | zero_poly(tp); 172 | tp[0] = gexp[i]; /* set up x+a^n */ 173 | tp[1] = 1; 174 | 175 | mult_polys(genpoly, tp, tp1); 176 | copy_poly(tp1, genpoly); 177 | } 178 | } 179 | 180 | /* Simulate a LFSR with generator polynomial for n byte RS code. 181 | * Pass in a pointer to the data array, and amount of data. 182 | * 183 | * The parity bytes are deposited into pBytes[], and the whole message 184 | * and parity are copied to dest to make a codeword. 185 | * 186 | */ 187 | 188 | void 189 | encode_data (unsigned char msg[], int nbytes, unsigned char dst[]) 190 | { 191 | int i ,dbyte, j; 192 | unsigned char LFSR[MAXNPAR+1]; 193 | 194 | for(i=0; i < NPAR+1; i++) 195 | LFSR[i]=0; 196 | 197 | // for (i = 0; i < nbytes; i++) 198 | for (i = nbytes-1; i >= 0; i--) // Order reversed for compatibility wiyh Rick' Code 199 | { 200 | dbyte = msg[i] ^ LFSR[NPAR-1]; 201 | for (j = NPAR-1; j > 0; j--) 202 | { 203 | LFSR[j] = LFSR[j-1] ^ gmult(genPoly[j], dbyte); 204 | } 205 | LFSR[0] = gmult(genPoly[0], dbyte); 206 | } 207 | 208 | // return the parity bytes 209 | 210 | memcpy(dst, LFSR, NPAR); 211 | } 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /ardop1ofdm/FFT.c: -------------------------------------------------------------------------------- 1 | // FFT Code 2 | /* 3 | '******************************************************************** 4 | ' Execution time for a 2048 point FFT on a 1700 MHz P4 was about 5 ms) 5 | ' Some optimization could be made if only real inputs are insured. 6 | ' Rick Muething KN6KB, Mar 31, 2004 7 | '******************************************************************** 8 | '-------------------------------------------------------------------- 9 | ' VB FFT Release 2-B 10 | ' by Murphy McCauley (MurphyMc@Concentric.NET) 11 | ' 10/01/99 12 | '-------------------------------------------------------------------- 13 | ' About: 14 | ' This code is very, very heavily based on Don Cross's fourier.pas 15 | ' Turbo Pascal Unit for calculating the Fast Fourier Transform. 16 | ' I've not implemented all of his functions, though I may well do 17 | ' so in the future. 18 | ' For more info, you can contact me by email, check my website at: 19 | ' http://www.fullspectrum.com/deeth/ 20 | ' or check Don Cross's FFT web page at: 21 | ' http://www.intersrv.com/~dcross/fft.html 22 | ' You also may be intrested in the FFT.DLL that I put together based 23 | ' on Don Cross's FFT C code. It's callable with Visual Basic and 24 | ' includes VB declares. You can get it from either website. 25 | '-------------------------------------------------------------------- 26 | ' History of Release 2-B: 27 | ' Fixed a couple of errors that resulted from me mucking about with 28 | ' variable names after implementation and not re-checking. BAD ME. 29 | ' -------- 30 | ' History of Release 2: 31 | ' Added FrequencyOfIndex() which is Don Cross's Index_to_frequency(). 32 | ' FourierTransform() can now do inverse transforms. 33 | ' Added CalcFrequency() which can do a transform for a single 34 | ' frequency. 35 | '-------------------------------------------------------------------- 36 | ' Usage: 37 | ' The useful functions are: 38 | ' FourierTransform() performs a Fast Fourier Transform on an pair of 39 | ' Double arrays -- one real, one imaginary. Don't want/need 40 | ' imaginary numbers? Just use an array of 0s. This function can 41 | ' also do inverse FFTs. 42 | ' FrequencyOfIndex() can tell you what actual frequency a given index 43 | ' corresponds to. 44 | ' CalcFrequency() transforms a single frequency. 45 | '-------------------------------------------------------------------- 46 | ' Notes: 47 | ' All arrays must be 0 based (i.e. Dim TheArray(0 To 1023) or 48 | ' Dim TheArray(1023)). 49 | ' The number of samples must be a power of two (i.e. 2^x). 50 | ' FrequencyOfIndex() and CalcFrequency() haven't been tested much. 51 | ' Use this ENTIRELY AT YOUR OWN RISK. 52 | '-------------------------------------------------------------------- 53 | */ 54 | 55 | #include 56 | 57 | #ifdef M_PI 58 | #undef M_PI 59 | #endif 60 | 61 | #define M_PI 3.1415926f 62 | 63 | int ipow(int base, int exp) 64 | { 65 | int result = 1; 66 | while (exp) 67 | { 68 | if (exp & 1) 69 | result *= base; 70 | exp >>= 1; 71 | base *= base; 72 | } 73 | 74 | return result; 75 | } 76 | 77 | int NumberOfBitsNeeded(int PowerOfTwo) 78 | { 79 | int i; 80 | 81 | for (i = 0; i <= 16; i++) 82 | { 83 | if ((PowerOfTwo & ipow(2, i)) != 0) 84 | return i; 85 | 86 | } 87 | return 0; 88 | } 89 | 90 | 91 | int ReverseBits(int Index, int NumBits) 92 | { 93 | int i, Rev = 0; 94 | 95 | for (i = 0; i < NumBits; i++) 96 | { 97 | Rev = (Rev * 2) | (Index & 1); 98 | Index = Index /2; 99 | } 100 | 101 | return Rev; 102 | } 103 | 104 | void FourierTransform(int NumSamples, short * RealIn, float * RealOut, float * ImagOut, int InverseTransform) 105 | { 106 | float AngleNumerator; 107 | unsigned char NumBits; 108 | 109 | int I, j, K, n, BlockSize, BlockEnd; 110 | float DeltaAngle, DeltaAr; 111 | float Alpha, Beta; 112 | float TR, TI, AR, AI; 113 | 114 | if (InverseTransform) 115 | AngleNumerator = -2.0f * M_PI; 116 | else 117 | AngleNumerator = 2.0f * M_PI; 118 | 119 | NumBits = NumberOfBitsNeeded(NumSamples); 120 | 121 | for (I = 0; I < NumSamples; I++) 122 | { 123 | j = ReverseBits(I, NumBits); 124 | RealOut[j] = RealIn[I]; 125 | ImagOut[j] = 0.0f; // Not using I in ImageIn[I]; 126 | } 127 | 128 | BlockEnd = 1; 129 | BlockSize = 2; 130 | 131 | while (BlockSize <= NumSamples) 132 | { 133 | DeltaAngle = AngleNumerator / BlockSize; 134 | Alpha = sinf(0.5f * DeltaAngle); 135 | Alpha = 2.0f * Alpha * Alpha; 136 | Beta = sinf(DeltaAngle); 137 | 138 | I = 0; 139 | 140 | while (I < NumSamples) 141 | { 142 | AR = 1.0f; 143 | AI = 0.0f; 144 | 145 | j = I; 146 | 147 | for (n = 0; n < BlockEnd; n++) 148 | { 149 | K = j + BlockEnd; 150 | TR = AR * RealOut[K] - AI * ImagOut[K]; 151 | TI = AI * RealOut[K] + AR * ImagOut[K]; 152 | RealOut[K] = RealOut[j] - TR; 153 | ImagOut[K] = ImagOut[j] - TI; 154 | RealOut[j] = RealOut[j] + TR; 155 | ImagOut[j] = ImagOut[j] + TI; 156 | DeltaAr = Alpha * AR + Beta * AI; 157 | AI = AI - (Alpha * AI - Beta * AR); 158 | AR = AR - DeltaAr; 159 | j = j + 1; 160 | } 161 | I = I + BlockSize; 162 | } 163 | BlockEnd = BlockSize; 164 | BlockSize = BlockSize * 2; 165 | } 166 | 167 | if (InverseTransform) 168 | { 169 | // Normalize the resulting time samples... 170 | 171 | for (I = 0; I < NumSamples; I++) 172 | { 173 | RealOut[I] = RealOut[I] / NumSamples; 174 | ImagOut[I] = ImagOut[I] / NumSamples; 175 | } 176 | } 177 | } 178 | 179 | 180 | -------------------------------------------------------------------------------- /ardop2ofdm/FFT.c: -------------------------------------------------------------------------------- 1 | // FFT Code 2 | /* 3 | '******************************************************************** 4 | ' Execution time for a 2048 point FFT on a 1700 MHz P4 was about 5 ms) 5 | ' Some optimization could be made if only real inputs are insured. 6 | ' Rick Muething KN6KB, Mar 31, 2004 7 | '******************************************************************** 8 | '-------------------------------------------------------------------- 9 | ' VB FFT Release 2-B 10 | ' by Murphy McCauley (MurphyMc@Concentric.NET) 11 | ' 10/01/99 12 | '-------------------------------------------------------------------- 13 | ' About: 14 | ' This code is very, very heavily based on Don Cross's fourier.pas 15 | ' Turbo Pascal Unit for calculating the Fast Fourier Transform. 16 | ' I've not implemented all of his functions, though I may well do 17 | ' so in the future. 18 | ' For more info, you can contact me by email, check my website at: 19 | ' http://www.fullspectrum.com/deeth/ 20 | ' or check Don Cross's FFT web page at: 21 | ' http://www.intersrv.com/~dcross/fft.html 22 | ' You also may be intrested in the FFT.DLL that I put together based 23 | ' on Don Cross's FFT C code. It's callable with Visual Basic and 24 | ' includes VB declares. You can get it from either website. 25 | '-------------------------------------------------------------------- 26 | ' History of Release 2-B: 27 | ' Fixed a couple of errors that resulted from me mucking about with 28 | ' variable names after implementation and not re-checking. BAD ME. 29 | ' -------- 30 | ' History of Release 2: 31 | ' Added FrequencyOfIndex() which is Don Cross's Index_to_frequency(). 32 | ' FourierTransform() can now do inverse transforms. 33 | ' Added CalcFrequency() which can do a transform for a single 34 | ' frequency. 35 | '-------------------------------------------------------------------- 36 | ' Usage: 37 | ' The useful functions are: 38 | ' FourierTransform() performs a Fast Fourier Transform on an pair of 39 | ' Double arrays -- one real, one imaginary. Don't want/need 40 | ' imaginary numbers? Just use an array of 0s. This function can 41 | ' also do inverse FFTs. 42 | ' FrequencyOfIndex() can tell you what actual frequency a given index 43 | ' corresponds to. 44 | ' CalcFrequency() transforms a single frequency. 45 | '-------------------------------------------------------------------- 46 | ' Notes: 47 | ' All arrays must be 0 based (i.e. Dim TheArray(0 To 1023) or 48 | ' Dim TheArray(1023)). 49 | ' The number of samples must be a power of two (i.e. 2^x). 50 | ' FrequencyOfIndex() and CalcFrequency() haven't been tested much. 51 | ' Use this ENTIRELY AT YOUR OWN RISK. 52 | '-------------------------------------------------------------------- 53 | */ 54 | 55 | #include 56 | 57 | #ifdef M_PI 58 | #undef M_PI 59 | #endif 60 | 61 | #define M_PI 3.1415926f 62 | 63 | int ipow(int base, int exp) 64 | { 65 | int result = 1; 66 | while (exp) 67 | { 68 | if (exp & 1) 69 | result *= base; 70 | exp >>= 1; 71 | base *= base; 72 | } 73 | 74 | return result; 75 | } 76 | 77 | int NumberOfBitsNeeded(int PowerOfTwo) 78 | { 79 | int i; 80 | 81 | for (i = 0; i <= 16; i++) 82 | { 83 | if ((PowerOfTwo & ipow(2, i)) != 0) 84 | return i; 85 | 86 | } 87 | return 0; 88 | } 89 | 90 | 91 | int ReverseBits(int Index, int NumBits) 92 | { 93 | int i, Rev = 0; 94 | 95 | for (i = 0; i < NumBits; i++) 96 | { 97 | Rev = (Rev * 2) | (Index & 1); 98 | Index = Index /2; 99 | } 100 | 101 | return Rev; 102 | } 103 | 104 | void FourierTransform(int NumSamples, short * RealIn, float * RealOut, float * ImagOut, int InverseTransform) 105 | { 106 | float AngleNumerator; 107 | unsigned char NumBits; 108 | 109 | int i, j, K, n, BlockSize, BlockEnd; 110 | float DeltaAngle, DeltaAr; 111 | float Alpha, Beta; 112 | float TR, TI, AR, AI; 113 | 114 | if (InverseTransform) 115 | AngleNumerator = -2.0f * M_PI; 116 | else 117 | AngleNumerator = 2.0f * M_PI; 118 | 119 | NumBits = NumberOfBitsNeeded(NumSamples); 120 | 121 | for (i = 0; i < NumSamples; i++) 122 | { 123 | j = ReverseBits(i, NumBits); 124 | RealOut[j] = RealIn[i]; 125 | ImagOut[j] = 0.0f; // Not using i in ImageIn[i]; 126 | } 127 | 128 | BlockEnd = 1; 129 | BlockSize = 2; 130 | 131 | while (BlockSize <= NumSamples) 132 | { 133 | DeltaAngle = AngleNumerator / BlockSize; 134 | Alpha = sinf(0.5f * DeltaAngle); 135 | Alpha = 2.0f * Alpha * Alpha; 136 | Beta = sinf(DeltaAngle); 137 | 138 | i = 0; 139 | 140 | while (i < NumSamples) 141 | { 142 | AR = 1.0f; 143 | AI = 0.0f; 144 | 145 | j = i; 146 | 147 | for (n = 0; n < BlockEnd; n++) 148 | { 149 | K = j + BlockEnd; 150 | TR = AR * RealOut[K] - AI * ImagOut[K]; 151 | TI = AI * RealOut[K] + AR * ImagOut[K]; 152 | RealOut[K] = RealOut[j] - TR; 153 | ImagOut[K] = ImagOut[j] - TI; 154 | RealOut[j] = RealOut[j] + TR; 155 | ImagOut[j] = ImagOut[j] + TI; 156 | DeltaAr = Alpha * AR + Beta * AI; 157 | AI = AI - (Alpha * AI - Beta * AR); 158 | AR = AR - DeltaAr; 159 | j = j + 1; 160 | } 161 | i = i + BlockSize; 162 | } 163 | BlockEnd = BlockSize; 164 | BlockSize = BlockSize * 2; 165 | } 166 | 167 | if (InverseTransform) 168 | { 169 | // Normalize the resulting time samples... 170 | 171 | for (i = 0; i < NumSamples; i++) 172 | { 173 | RealOut[i] = RealOut[i] / NumSamples; 174 | ImagOut[i] = ImagOut[i] / NumSamples; 175 | } 176 | } 177 | } 178 | 179 | 180 | -------------------------------------------------------------------------------- /ardop2ofdm/LinSerial.c: -------------------------------------------------------------------------------- 1 | // ARDOP TNC Host Interface 2 | 3 | 4 | #define HANDLE int 5 | 6 | #define _XOPEN_SOURCE 600 7 | #define _GNU_SOURCE 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "ARDOPC.h" 23 | 24 | HANDLE hDevice; 25 | 26 | VOID ProcessSCSPacket(UCHAR * rxbuffer, unsigned int Length); 27 | BOOL WriteCOMBlock(HANDLE fd, char * Block, int BytesToWrite); 28 | 29 | 30 | //#include 31 | 32 | HANDLE LinuxOpenPTY(char * Name) 33 | { 34 | // Open a Virtual COM Port 35 | 36 | HANDLE hDevice, slave; 37 | char slavedevice[80]; 38 | int ret; 39 | u_long param=1; 40 | struct termios term; 41 | 42 | #ifdef MACBPQ 43 | 44 | // Create a pty pair 45 | 46 | openpty(&hDevice, &slave, &slavedevice[0], NULL, NULL); 47 | close(slave); 48 | 49 | #else 50 | 51 | hDevice = posix_openpt(O_RDWR|O_NOCTTY); 52 | 53 | if (hDevice == -1 || grantpt (hDevice) == -1 || unlockpt (hDevice) == -1 || 54 | ptsname_r(hDevice, slavedevice, 80) != 0) 55 | { 56 | perror("Create PTY pair failed"); 57 | return -1; 58 | } 59 | 60 | #endif 61 | 62 | printf("slave device: %s\n", slavedevice); 63 | 64 | if (tcgetattr(hDevice, &term) == -1) 65 | { 66 | perror("tty_speed: tcgetattr"); 67 | return FALSE; 68 | } 69 | 70 | cfmakeraw(&term); 71 | 72 | if (tcsetattr(hDevice, TCSANOW, &term) == -1) 73 | { 74 | perror("tcsetattr"); 75 | return -1; 76 | } 77 | 78 | ioctl(hDevice, FIONBIO, ¶m); 79 | 80 | chmod(slavedevice, S_IRUSR|S_IRGRP|S_IWUSR|S_IWGRP|S_IROTH|S_IWOTH); 81 | 82 | unlink (Name); 83 | 84 | ret = symlink (slavedevice, Name); 85 | 86 | if (ret == 0) 87 | printf ("symlink to %s created\n", Name); 88 | else 89 | printf ("symlink to %s failed\n", Name); 90 | 91 | return hDevice; 92 | } 93 | 94 | 95 | int SerialSendData(UCHAR * Message,int MsgLen) 96 | { 97 | // Linux uses normal IO for all ports 98 | 99 | WriteCOMBlock(hDevice, Message, MsgLen); 100 | return 0; 101 | } 102 | 103 | int xSerialGetData(UCHAR * Message, unsigned int BufLen, unsigned long * MsgLen) 104 | { 105 | return 0; 106 | } 107 | 108 | 109 | BOOL SerialHostInit() 110 | { 111 | hDevice = LinuxOpenPTY(HostPort); 112 | 113 | if (hDevice) 114 | { 115 | printf("PTY Handle %d\n", hDevice); 116 | // Set up buffer pointers 117 | } 118 | return TRUE; 119 | } 120 | 121 | 122 | int ReadCOMBlock(HANDLE fd, char * Block, int MaxLength) 123 | { 124 | int Length; 125 | 126 | Length = read(fd, Block, MaxLength); 127 | 128 | if (Length < 0) 129 | { 130 | return 0; 131 | } 132 | 133 | return Length; 134 | } 135 | 136 | 137 | static struct speed_struct 138 | { 139 | int user_speed; 140 | speed_t termios_speed; 141 | } speed_table[] = { 142 | {300, B300}, 143 | {600, B600}, 144 | {1200, B1200}, 145 | {2400, B2400}, 146 | {4800, B4800}, 147 | {9600, B9600}, 148 | {19200, B19200}, 149 | {38400, B38400}, 150 | {57600, B57600}, 151 | {115200, B115200}, 152 | {-1, B0} 153 | }; 154 | 155 | 156 | HANDLE OpenCOMPort(VOID * Port, int speed, BOOL SetDTR, BOOL SetRTS, BOOL Quiet, int Stopbits) 157 | {; 158 | char buf[100]; 159 | 160 | // Linux Version. 161 | 162 | int fd; 163 | int hwflag = 0; 164 | u_long param=1; 165 | struct termios term; 166 | struct speed_struct *s; 167 | 168 | // As Serial ports under linux can have all sorts of odd names, the code assumes that 169 | // they are symlinked to a com1-com255 in the BPQ Directory (normally the one it is started from 170 | 171 | if ((fd = open(Port, O_RDWR | O_NDELAY)) == -1) 172 | { 173 | if (Quiet == 0) 174 | { 175 | perror("Com Open Failed"); 176 | sprintf(buf," %s could not be opened", (char *)Port); 177 | Debugprintf(buf); 178 | } 179 | return 0; 180 | } 181 | 182 | // Validate Speed Param 183 | 184 | for (s = speed_table; s->user_speed != -1; s++) 185 | if (s->user_speed == speed) 186 | break; 187 | 188 | if (s->user_speed == -1) 189 | { 190 | fprintf(stderr, "tty_speed: invalid speed %d", speed); 191 | return FALSE; 192 | } 193 | 194 | if (tcgetattr(fd, &term) == -1) 195 | { 196 | perror("tty_speed: tcgetattr"); 197 | return FALSE; 198 | } 199 | 200 | cfmakeraw(&term); 201 | cfsetispeed(&term, s->termios_speed); 202 | cfsetospeed(&term, s->termios_speed); 203 | 204 | if (tcsetattr(fd, TCSANOW, &term) == -1) 205 | { 206 | perror("tty_speed: tcsetattr"); 207 | return FALSE; 208 | } 209 | 210 | ioctl(fd, FIONBIO, ¶m); 211 | 212 | Debugprintf("LinBPQ Port %s fd %d", Port, fd); 213 | 214 | return fd; 215 | } 216 | 217 | BOOL WriteCOMBlock(HANDLE fd, char * Block, int BytesToWrite) 218 | { 219 | // Some systems seem to have a very small max write size 220 | 221 | int ToSend = BytesToWrite; 222 | int Sent = 0, ret; 223 | 224 | while (ToSend) 225 | { 226 | ret = write(fd, &Block[Sent], ToSend); 227 | 228 | if (ret >= ToSend) 229 | return TRUE; 230 | 231 | if (ret == -1) 232 | { 233 | if (errno != 11 && errno != 35) // Would Block 234 | return FALSE; 235 | 236 | usleep(10000); 237 | ret = 0; 238 | } 239 | 240 | Sent += ret; 241 | ToSend -= ret; 242 | } 243 | return TRUE; 244 | } 245 | 246 | VOID CloseCOMPort(HANDLE fd) 247 | { 248 | close(fd); 249 | } 250 | 251 | VOID COMSetDTR(HANDLE fd) 252 | { 253 | int status; 254 | 255 | ioctl(fd, TIOCMGET, &status); 256 | status |= TIOCM_DTR; 257 | ioctl(fd, TIOCMSET, &status); 258 | } 259 | 260 | VOID COMClearDTR(HANDLE fd) 261 | { 262 | int status; 263 | 264 | ioctl(fd, TIOCMGET, &status); 265 | status &= ~TIOCM_DTR; 266 | ioctl(fd, TIOCMSET, &status); 267 | } 268 | 269 | VOID COMSetRTS(HANDLE fd) 270 | { 271 | int status; 272 | 273 | if (ioctl(fd, TIOCMGET, &status) == -1) 274 | perror("ARDOP PTT TIOCMGET"); 275 | status |= TIOCM_RTS; 276 | if (ioctl(fd, TIOCMSET, &status) == -1) 277 | perror("ARDOP PTT TIOCMSET"); 278 | } 279 | 280 | VOID COMClearRTS(HANDLE fd) 281 | { 282 | int status; 283 | 284 | if (ioctl(fd, TIOCMGET, &status) == -1) 285 | perror("ARDOP PTT TIOCMGET"); 286 | status &= ~TIOCM_RTS; 287 | if (ioctl(fd, TIOCMSET, &status) == -1) 288 | perror("ARDOP PTT TIOCMSET"); 289 | } 290 | 291 | 292 | UCHAR RXBUFFER[500]; // Long enough for stuffed Host Mode frame 293 | 294 | int RXBPtr = 0; 295 | 296 | 297 | VOID SerialHostPoll() 298 | { 299 | unsigned long Read = 0; 300 | 301 | Read = ReadCOMBlock(hDevice, &RXBUFFER[RXBPtr], 499 - RXBPtr); 302 | 303 | if (Read) 304 | { 305 | RXBPtr += Read; 306 | ProcessSCSPacket(RXBUFFER, RXBPtr); 307 | } 308 | 309 | // if (UseKISS) 310 | // KISSTCPPoll(); 311 | } 312 | 313 | VOID PutString(UCHAR * Msg) 314 | { 315 | SerialSendData(Msg, strlen(Msg)); 316 | } 317 | 318 | int PutChar(UCHAR c) 319 | { 320 | SerialSendData(&c, 1); 321 | return 0; 322 | } 323 | 324 | void CatWrite(char * Buffer, int Len) 325 | { 326 | WriteDebugLog(5, "CAT Write Len %d %s", Len, Buffer); 327 | if (hCATDevice) 328 | WriteCOMBlock(hCATDevice, Buffer, Len); 329 | } -------------------------------------------------------------------------------- /ardop1ofdm/LinSerial.c: -------------------------------------------------------------------------------- 1 | // ARDOP TNC Host Interface 2 | 3 | 4 | #define HANDLE int 5 | 6 | #define _XOPEN_SOURCE 600 7 | #define _GNU_SOURCE 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "ARDOPC.h" 23 | 24 | HANDLE hDevice; 25 | 26 | VOID ProcessSCSPacket(UCHAR * rxbuffer, unsigned int Length); 27 | BOOL WriteCOMBlock(HANDLE fd, char * Block, int BytesToWrite); 28 | 29 | 30 | //#include 31 | 32 | HANDLE LinuxOpenPTY(char * Name) 33 | { 34 | // Open a Virtual COM Port 35 | 36 | HANDLE hDevice, slave; 37 | char slavedevice[80]; 38 | int ret; 39 | u_long param=1; 40 | struct termios term; 41 | 42 | #ifdef MACBPQ 43 | 44 | // Create a pty pair 45 | 46 | openpty(&hDevice, &slave, &slavedevice[0], NULL, NULL); 47 | close(slave); 48 | 49 | #else 50 | 51 | hDevice = posix_openpt(O_RDWR|O_NOCTTY); 52 | 53 | if (hDevice == -1 || grantpt (hDevice) == -1 || unlockpt (hDevice) == -1 || 54 | ptsname_r(hDevice, slavedevice, 80) != 0) 55 | { 56 | perror("Create PTY pair failed"); 57 | return -1; 58 | } 59 | 60 | #endif 61 | 62 | printf("slave device: %s\n", slavedevice); 63 | 64 | if (tcgetattr(hDevice, &term) == -1) 65 | { 66 | perror("tty_speed: tcgetattr"); 67 | return FALSE; 68 | } 69 | 70 | cfmakeraw(&term); 71 | 72 | if (tcsetattr(hDevice, TCSANOW, &term) == -1) 73 | { 74 | perror("tcsetattr"); 75 | return -1; 76 | } 77 | 78 | ioctl(hDevice, FIONBIO, ¶m); 79 | 80 | chmod(slavedevice, S_IRUSR|S_IRGRP|S_IWUSR|S_IWGRP|S_IROTH|S_IWOTH); 81 | 82 | unlink (Name); 83 | 84 | ret = symlink (slavedevice, Name); 85 | 86 | if (ret == 0) 87 | printf ("symlink to %s created\n", Name); 88 | else 89 | printf ("symlink to %s failed\n", Name); 90 | 91 | return hDevice; 92 | } 93 | 94 | 95 | int SerialSendData(UCHAR * Message,int MsgLen) 96 | { 97 | // Linux uses normal IO for all ports 98 | 99 | WriteCOMBlock(hDevice, Message, MsgLen); 100 | return 0; 101 | } 102 | 103 | int xSerialGetData(UCHAR * Message, unsigned int BufLen, unsigned long * MsgLen) 104 | { 105 | return 0; 106 | } 107 | 108 | 109 | BOOL SerialHostInit() 110 | { 111 | hDevice = LinuxOpenPTY(HostPort); 112 | 113 | if (hDevice) 114 | { 115 | printf("PTY Handle %d\n", hDevice); 116 | // Set up buffer pointers 117 | } 118 | return TRUE; 119 | } 120 | 121 | 122 | int ReadCOMBlock(HANDLE fd, char * Block, int MaxLength) 123 | { 124 | int Length; 125 | 126 | Length = read(fd, Block, MaxLength); 127 | 128 | if (Length < 0) 129 | { 130 | return 0; 131 | } 132 | 133 | return Length; 134 | } 135 | 136 | 137 | static struct speed_struct 138 | { 139 | int user_speed; 140 | speed_t termios_speed; 141 | } speed_table[] = { 142 | {300, B300}, 143 | {600, B600}, 144 | {1200, B1200}, 145 | {2400, B2400}, 146 | {4800, B4800}, 147 | {9600, B9600}, 148 | {19200, B19200}, 149 | {38400, B38400}, 150 | {57600, B57600}, 151 | {115200, B115200}, 152 | {-1, B0} 153 | }; 154 | 155 | 156 | HANDLE OpenCOMPort(VOID * Port, int speed, BOOL SetDTR, BOOL SetRTS, BOOL Quiet, int Stopbits) 157 | {; 158 | char buf[100]; 159 | 160 | // Linux Version. 161 | 162 | int fd; 163 | int hwflag = 0; 164 | u_long param=1; 165 | struct termios term; 166 | struct speed_struct *s; 167 | 168 | // As Serial ports under linux can have all sorts of odd names, the code assumes that 169 | // they are symlinked to a com1-com255 in the BPQ Directory (normally the one it is started from 170 | 171 | if ((fd = open(Port, O_RDWR | O_NDELAY)) == -1) 172 | { 173 | if (Quiet == 0) 174 | { 175 | perror("Com Open Failed"); 176 | sprintf(buf," %s could not be opened", Port); 177 | Debugprintf(buf); 178 | } 179 | return 0; 180 | } 181 | 182 | // Validate Speed Param 183 | 184 | for (s = speed_table; s->user_speed != -1; s++) 185 | if (s->user_speed == speed) 186 | break; 187 | 188 | if (s->user_speed == -1) 189 | { 190 | fprintf(stderr, "tty_speed: invalid speed %d", speed); 191 | return FALSE; 192 | } 193 | 194 | if (tcgetattr(fd, &term) == -1) 195 | { 196 | perror("tty_speed: tcgetattr"); 197 | return FALSE; 198 | } 199 | 200 | cfmakeraw(&term); 201 | cfsetispeed(&term, s->termios_speed); 202 | cfsetospeed(&term, s->termios_speed); 203 | 204 | if (tcsetattr(fd, TCSANOW, &term) == -1) 205 | { 206 | perror("tty_speed: tcsetattr"); 207 | return FALSE; 208 | } 209 | 210 | ioctl(fd, FIONBIO, ¶m); 211 | 212 | Debugprintf("LinBPQ Port %s fd %d", Port, fd); 213 | 214 | return fd; 215 | } 216 | 217 | BOOL WriteCOMBlock(HANDLE fd, char * Block, int BytesToWrite) 218 | { 219 | // Some systems seem to have a very small max write size 220 | 221 | int ToSend = BytesToWrite; 222 | int Sent = 0, ret; 223 | 224 | while (ToSend) 225 | { 226 | ret = write(fd, &Block[Sent], ToSend); 227 | 228 | if (ret >= ToSend) 229 | return TRUE; 230 | 231 | if (ret == -1) 232 | { 233 | if (errno != 11 && errno != 35) // Would Block 234 | return FALSE; 235 | 236 | usleep(10000); 237 | ret = 0; 238 | } 239 | 240 | Sent += ret; 241 | ToSend -= ret; 242 | } 243 | return TRUE; 244 | } 245 | 246 | VOID CloseCOMPort(HANDLE fd) 247 | { 248 | close(fd); 249 | } 250 | 251 | VOID COMSetDTR(HANDLE fd) 252 | { 253 | int status; 254 | 255 | ioctl(fd, TIOCMGET, &status); 256 | status |= TIOCM_DTR; 257 | ioctl(fd, TIOCMSET, &status); 258 | } 259 | 260 | VOID COMClearDTR(HANDLE fd) 261 | { 262 | int status; 263 | 264 | ioctl(fd, TIOCMGET, &status); 265 | status &= ~TIOCM_DTR; 266 | ioctl(fd, TIOCMSET, &status); 267 | } 268 | 269 | VOID COMSetRTS(HANDLE fd) 270 | { 271 | int status; 272 | 273 | if (ioctl(fd, TIOCMGET, &status) == -1) 274 | perror("ARDOP PTT TIOCMGET"); 275 | status |= TIOCM_RTS; 276 | if (ioctl(fd, TIOCMSET, &status) == -1) 277 | perror("ARDOP PTT TIOCMSET"); 278 | } 279 | 280 | VOID COMClearRTS(HANDLE fd) 281 | { 282 | int status; 283 | 284 | if (ioctl(fd, TIOCMGET, &status) == -1) 285 | perror("ARDOP PTT TIOCMGET"); 286 | status &= ~TIOCM_RTS; 287 | if (ioctl(fd, TIOCMSET, &status) == -1) 288 | perror("ARDOP PTT TIOCMSET"); 289 | } 290 | 291 | 292 | UCHAR RXBUFFER[500]; // Long enough for stuffed Host Mode frame 293 | 294 | extern volatile int RXBPtr; 295 | 296 | VOID SerialHostPoll() 297 | { 298 | unsigned long Read = 0; 299 | 300 | Read = ReadCOMBlock(hDevice, &RXBUFFER[RXBPtr], 499 - RXBPtr); 301 | 302 | if (Read) 303 | { 304 | RXBPtr += Read; 305 | ProcessSCSPacket(RXBUFFER, RXBPtr); 306 | } 307 | 308 | // if (UseKISS) 309 | // KISSTCPPoll(); 310 | } 311 | 312 | VOID PutString(UCHAR * Msg) 313 | { 314 | SerialSendData(Msg, strlen(Msg)); 315 | } 316 | 317 | int PutChar(UCHAR c) 318 | { 319 | SerialSendData(&c, 1); 320 | return 0; 321 | } 322 | 323 | void CatWrite(char * Buffer, int Len) 324 | { 325 | WriteDebugLog(5, "CAT Write Len %d %s", Len, Buffer); 326 | if (hCATDevice) 327 | WriteCOMBlock(hCATDevice, Buffer, Len); 328 | } 329 | -------------------------------------------------------------------------------- /ardop1ofdm/UZ7HOFEC.c: -------------------------------------------------------------------------------- 1 | // Routines to support UZ7HO's PSK FEC Mode 2 | 3 | 4 | // 4 * 100 baud carriers spaced at 175 HZ intervals. BPSK 5 | 6 | #include "ARDOPC.h" 7 | 8 | #pragma warning(disable : 4244) // Code does lots of int float to int 9 | 10 | 11 | // Get sample sync. ARDOP seems to do it by comparing a generated 1500 Hz 12 | // tone with received signal and finding sample position that gives best 13 | // correlation. This works as ARDOP has a 1500 Hz leader. Can we apply this here?? 14 | 15 | 16 | 17 | 18 | 19 | // Decode 1 carrier of PSK signal 20 | 21 | // UZ7HO Version. Similar to ARDOP, but can run on unmixed 22 | 23 | int ComputeAng1_Ang2(int intAng1, int intAng2); 24 | void GoertzelRealImag(short intRealIn[], int intPtr, int N, float m, float * dblReal, float * dblImag); 25 | int Track1CarPSK(int intCarFreq, int PSKMode, float dblUnfilteredPhase, BOOL blnInit); 26 | void MixNCOFilter(short * intNewSamples, int Length, float dblOffsetHz); 27 | 28 | 29 | float CarFreq; 30 | int UZ7HOIndex = -1; 31 | 32 | extern short intPhases[8][8]; // We will decode as soon as we have 4 or 8 depending on mode 33 | // (but need one set per carrier) 34 | 35 | extern short intMags[8][8]; 36 | extern int intPhasesLen; 37 | extern short intPSKPhase_1[8], intPSKPhase_0[8]; 38 | extern int Corrections; 39 | extern int intSampPerSym; 40 | extern char strMod[16]; 41 | extern float dblOffsetHz; 42 | extern short intFilteredMixedSamples[3600]; // Get Frame Type need 2400 and we may add 1200 43 | extern int intFilteredMixedSamplesLength; 44 | 45 | 46 | int Demod1CarPSKUZ7HO(short * Samples, int Start, int Carrier) 47 | { 48 | // Converts intSample to an array of differential phase and magnitude values for the Specific Carrier Freq 49 | // intPtr should be pointing to the approximate start of the first reference/training symbol (1 of 3) 50 | // intPhase() is an array of phase values (in milliradians range of 0 to 6283) for each symbol 51 | // intMag() is an array of Magnitude values (not used in PSK decoding but for constellation plotting or QAM decoding) 52 | // Objective is to use Minimum Phase Error Tracking to maintain optimum pointer position 53 | 54 | // Decodes 8 successive symbols (960 bits) 55 | 56 | float dblReal, dblImag; 57 | int intMiliRadPerSample = CarFreq * M_PI / 6; 58 | int i; 59 | int intNumOfSymbols = 8; 60 | int origStart = Start; 61 | float dblFreqBin = CarFreq / 200.0f; //200 = 12000/60 62 | int intCP = 28; // This value selected for best decoding percentage (56%) and best Averag 4PSK Quality (77) on mpg +5 dB 63 | int intNforGoertzel = 60; 64 | int intDiff; 65 | int NewPhase; 66 | 67 | for (i = 0; i < intNumOfSymbols; i++) 68 | { 69 | GoertzelRealImag(Samples, Start + intCP, intNforGoertzel, dblFreqBin, &dblReal, &dblImag); 70 | intMags[Carrier][intPhasesLen] = sqrtf(powf(dblReal, 2) + powf(dblImag, 2)); 71 | NewPhase = 1000 * atan2f(dblImag, dblReal); 72 | 73 | intDiff = NewPhase - intPSKPhase_1[Carrier]; 74 | 75 | if (intDiff < 0) 76 | intDiff += 6284; 77 | 78 | intPhases[Carrier][intPhasesLen] = intDiff; 79 | 80 | Corrections = Track1CarPSK(CarFreq, strMod[0] - '0', atan2f(dblImag, dblReal), FALSE); 81 | 82 | // if (Corrections != 0) 83 | // { 84 | // Start += Corrections; 85 | // 86 | // GoertzelRealImag(Samples, Start + intCP, intNforGoertzel, dblFreqBin, &dblReal, &dblImag); 87 | // intPSKPhase_0[Carrier] = 1000 * atan2f(dblImag, dblReal); 88 | // } 89 | intPSKPhase_1[Carrier] = NewPhase; 90 | intPhasesLen++; 91 | Start += intSampPerSym; 92 | } 93 | // If AccumulateStats Then intPSKSymbolCnt += intPhase.Length 94 | 95 | return (Start - origStart); // Symbols we've consumed 96 | } 97 | 98 | 99 | 100 | 101 | BOOL LookforUZ7HOLeader(short * Samples, int nSamples) 102 | { 103 | // 4 100 baud carriers spaced at 175 HZint Used;. BPSK 104 | 105 | int Used; 106 | 107 | int OuterStart = 0, i, x, y; 108 | 109 | float carriers[4] = { 110 | 1500 - (1.5 * 175), 111 | 1500 - (0.5 * 175), 112 | 1500 + (0.5 * 175), 113 | 1500 + (1.5 * 175)}; 114 | 115 | // dblPhaseInc = 2 * M_PI * 1000 / 4; 116 | 117 | intSampPerSym = 120; 118 | intPhasesLen = 0; 119 | 120 | for (i= 0; i < 4; i++) 121 | { 122 | // dblFreqBin[i] = CarFrew / 200.0f; //200 = 12000/60 123 | // CarFreq -= 175; 124 | // intPSKPhase_1[i] = 0; 125 | } 126 | 127 | 128 | MixNCOFilter(Samples, nSamples, dblOffsetHz); // Mix and filter new samples (Mixing consumes all intRcvdSamples) 129 | OuterStart = 0; 130 | 131 | while (intFilteredMixedSamplesLength > (960 + 120)) // Experimental UZ7HO FSK Detect 132 | { 133 | if (UZ7HOIndex == -1) 134 | { 135 | // repeat decode with sample pointer incremented to get sample sync 136 | 137 | x = 0; 138 | y = 120; 139 | } 140 | else 141 | { 142 | x = UZ7HOIndex; 143 | y = x + 1; 144 | } 145 | for (i = x; i < y; i++) 146 | { 147 | char x1[10] = ""; 148 | char x2[10] = ""; 149 | char x3[10] = ""; 150 | char x4[10] = ""; 151 | int j; 152 | int Start = OuterStart; 153 | 154 | CarFreq = carriers[0]; 155 | 156 | Used = Demod1CarPSKUZ7HO(intFilteredMixedSamples, Start + i, 0); 157 | intPhasesLen -= 8; //intPSKMode; 158 | CarFreq = carriers[1]; 159 | 160 | Demod1CarPSKUZ7HO(intFilteredMixedSamples, Start + i, 1); 161 | intPhasesLen -= 8; //intPSKMode; 162 | CarFreq = carriers[2]; 163 | 164 | Demod1CarPSKUZ7HO(intFilteredMixedSamples, Start + i, 2); 165 | intPhasesLen -= 8; //intPSKMode; 166 | CarFreq = carriers[3]; 167 | 168 | Used = Demod1CarPSKUZ7HO(intFilteredMixedSamples, Start + i, 3); 169 | 170 | // Decode Phases. 0 = 180 shift 1 = no shift 171 | for (j = 0; j < 8; j++) 172 | { 173 | if (intPhases[0][j] < 1572 || intPhases[0][j] > 1572 * 3) 174 | x1[j] = '1'; 175 | else 176 | x1[j] = '0'; 177 | if (intPhases[1][j] < 1572 || intPhases[1][j] > 1572 * 3) 178 | x2[j] = '1'; 179 | else 180 | x2[j] = '0'; 181 | if (intPhases[2][j] < 1572 || intPhases[2][j] > 1572 * 3) 182 | x3[j] = '1'; 183 | else 184 | x3[j] = '0'; 185 | if (intPhases[3][j] < 1572 || intPhases[3][j] > 1572 * 3) 186 | x4[j] = '1'; 187 | else 188 | x4[j] = '0'; 189 | } 190 | 191 | // CorrectPhaseForTuningOffset(intPhases, intPhasesLen, strMod); 192 | 193 | printf("%d %d %d %d %d %d %d %d %d\n", 194 | i, intMags[0][0], intMags[0][1], intMags[0][2], intMags[0][3], 195 | intMags[0][4], intMags[0][5], intMags[0][6], intMags[0][7]); 196 | 197 | printf("%d %d %d %d %d %d %d %d %d\n", 198 | i, intPhases[0][0], intPhases[0][1], intPhases[0][2], intPhases[0][3], 199 | intPhases[0][4], intPhases[0][5], intPhases[0][6], intPhases[0][7]); 200 | 201 | printf ("%d %s %s %s %s \n", i, x1, x2, x3, x4); 202 | // i, intPhases[0][0], intPhases[0][1], intPhases[0][2], intPhases[0][3], 203 | // intPhases[0][4], intPhases[0][5], intPhases[0][6], intPhases[0][7]); 204 | 205 | // When we get the TXDelay preamble we should see all zeros 206 | 207 | if (UZ7HOIndex == -1) 208 | { 209 | if (strcmp(x1, "00000000") == 0 && 210 | strcmp(x2, "00000000") == 0 && 211 | strcmp(x3, "00000000") == 0 && 212 | strcmp(x4, "00000000") == 0 213 | ) 214 | { 215 | UZ7HOIndex = i + 1; 216 | if (UZ7HOIndex > 119) 217 | UZ7HOIndex -= 120; 218 | } 219 | } 220 | intPhasesLen = 0; 221 | } 222 | intFilteredMixedSamplesLength -= 960; 223 | OuterStart += 960; 224 | } 225 | memmove(intFilteredMixedSamples, 226 | &intFilteredMixedSamples[OuterStart], intFilteredMixedSamplesLength * 2); 227 | 228 | return FALSE; 229 | 230 | } // end of UZ7HO 231 | 232 | 233 | -------------------------------------------------------------------------------- /ardop1ofdm/NucleoSound.c: -------------------------------------------------------------------------------- 1 | // 2 | // Passes audio samples to the sound interface 3 | 4 | // Windows uses WaveOut 5 | 6 | // Nucleo uses DMA to the internal ADC and DAC 7 | 8 | // Linux will probably use ALSA 9 | 10 | // This is the Nucleo Version 11 | 12 | // Also has some platform specific routines 13 | 14 | #include 15 | #include "ARDOPC.h" 16 | 17 | void SetLED(int blnPTT); 18 | void stopDAC(); 19 | 20 | // Windows and Linux work with signed samples +- 32767 21 | // STM32 DAC uses unsigned 0 - 4095 22 | 23 | unsigned short buffer[2][1200]; // Two Transfer/DMA buffers of 0.1 Sec 24 | unsigned short work; 25 | 26 | extern volatile int adc_buffer_mem; 27 | 28 | #define SAMPLES_PER_BLOCK 1200 29 | 30 | extern uint16_t ADC_Buffer[2][SAMPLES_PER_BLOCK]; // stereo capture buffers 31 | 32 | //short audioInputBuffer[SAMPLES_PER_BLOCK]; Reuse DMA buffer 33 | 34 | int max, min, tot; 35 | 36 | BOOL Loopback = FALSE; 37 | //BOOL Loopback = TRUE; 38 | 39 | char CaptureDevice[] = "DMA"; 40 | char PlaybackDevice[] = "DMA"; 41 | 42 | char * CaptureDevices = CaptureDevice; 43 | char * PlaybackDevices = PlaybackDevice; 44 | 45 | int LastNow; 46 | 47 | int Number = 0; // Number waiting to be sent 48 | 49 | unsigned short * DMABuffer; 50 | 51 | #define KISSBufferSize 1024 52 | 53 | 54 | extern unsigned char rx_buffer[KISSBufferSize]; 55 | 56 | // Circular buffer pointers 57 | // volatile makes read-modify-write atomic 58 | 59 | volatile extern int rx_in; 60 | extern volatile int rx_out; 61 | 62 | #define MAX_KISS_LEN 2048 /* Spec calls for at least 1024. */ 63 | /* Might want to make it longer to accomodate */ 64 | /* maximum packet length. */ 65 | 66 | #define MAX_NOISE_LEN 100 67 | enum kiss_state_e { 68 | KS_SEARCHING, /* Looking for FEND to start KISS frame. */ 69 | KS_COLLECTING}; /* In process of collecting KISS frame. */ 70 | 71 | 72 | 73 | typedef struct kiss_frame_s { 74 | 75 | enum kiss_state_e state; 76 | 77 | unsigned char kiss_msg[MAX_KISS_LEN]; 78 | /* Leading FEND is optional. */ 79 | /* Contains escapes and ending FEND. */ 80 | int kiss_len; 81 | 82 | unsigned char noise[MAX_NOISE_LEN]; 83 | int noise_len; 84 | 85 | } kiss_frame_t; 86 | 87 | 88 | extern kiss_frame_t kf; /* Accumulated KISS frame and state of decoder. */ 89 | 90 | 91 | void printtick(char * msg) 92 | { 93 | Debugprintf("%s %i", msg, Now - LastNow); 94 | LastNow = Now; 95 | } 96 | 97 | extern volatile int ticks; 98 | 99 | unsigned int getTicks() 100 | { 101 | return ticks; 102 | } 103 | 104 | extern int kissdebug; 105 | void kiss_send_rec_packet (int chan, unsigned char *fbuf, int flen); 106 | 107 | 108 | void txSleep(int mS) 109 | { 110 | // called while waiting for next TX buffer. Run background processes 111 | 112 | unsigned char ch; 113 | 114 | if (rx_in != rx_out) 115 | { 116 | ch = rx_buffer[rx_out]; 117 | rx_out = (rx_out + 1) % KISSBufferSize; 118 | kiss_rec_byte (&kf, ch, kissdebug, kiss_send_rec_packet); 119 | } 120 | 121 | recv_process(); 122 | 123 | // Sleep(mS); 124 | } 125 | 126 | 127 | #include 128 | 129 | int PriorSize = 0; 130 | 131 | int Index = 0; // DMA Buffer being used 0 or 1 132 | int inIndex = 0; // DMA Buffer being used 0 or 1 133 | 134 | BOOL DMARunning = FALSE; // Used to start DMA on first write 135 | 136 | void InitSound() 137 | { 138 | Config_ADC_DMA(); 139 | Start_ADC_DMA(); 140 | } 141 | 142 | unsigned short * SendtoCard(unsigned short buf, int n) 143 | { 144 | if (Loopback) 145 | { 146 | // Loop back to decode for testing 147 | 148 | // ProcessNewSamples(buf, 1200); // signed 149 | } 150 | 151 | // Start DMA if first call 152 | 153 | if (DMARunning == FALSE) 154 | { 155 | StartDAC(); 156 | DMARunning = TRUE; 157 | } 158 | 159 | // wait for other DMA buffer to finish 160 | 161 | printtick("Start Wait"); // FOr timing tests 162 | 163 | while (1) 164 | { 165 | int chan = DMA_GetCurrentMemoryTarget(DMA1_Stream5); 166 | 167 | if (chan == Index) // we've started sending current buffer 168 | { 169 | Index = !Index; 170 | printtick("Stop Wait"); 171 | break; 172 | } 173 | txSleep(10); // Run background while waiting 174 | } 175 | return &buffer[Index][0]; 176 | } 177 | 178 | // // This generates a nice musical pattern for sound interface testing 179 | // for (t = 0; t < sizeof(buffer); ++t) 180 | // buffer[t] =((((t * (t >> 8 | t >> 9) & 46 & t >> 8)) ^ (t & t >> 13 | t >> 6)) & 0xFF); 181 | 182 | int min = 0, max = 0, leveltimer = 0; 183 | 184 | void multi_modem_process_sample (int chan, int audio_sample) ; 185 | 186 | void PollReceivedSamples() 187 | { 188 | // Process any captured samples 189 | // Ideally call at least every 100 mS, more than 200 will loose data 190 | 191 | // Process any received samples 192 | 193 | // convert the saved ADC 12-bit unsigned samples into 16-bit signed samples 194 | 195 | if (adc_buffer_mem >= 0 && adc_buffer_mem <= 1) 196 | { 197 | uint16_t *src = (uint16_t *)&ADC_Buffer[adc_buffer_mem]; // point to the DMA buffer where the ADC samples were saved 198 | // int16_t *dst = (int16_t *)&audioInputBuffer; // point to our own buffer where we are going to copy them too 199 | int16_t *dst = (int16_t *)src; // reuse input buffer 200 | short * ptr; 201 | 202 | // 12-bit unsigned to 16-bit signed 203 | 204 | int i; 205 | 206 | for (i = 0; i < SAMPLES_PER_BLOCK; i++) 207 | { 208 | register int32_t s1 = ((int16_t)(*src++) - 2048) << 4; // unsigned 12-bit to 16-bit signed .. ADC channel 1 209 | *dst++ = (int16_t)s1; 210 | tot += s1; 211 | if (s1 > max) 212 | max = s1; 213 | if (s1 < min) 214 | min = s1; 215 | } 216 | 217 | // serial.printf("Max %d min %d av %d\n", max, min, tot/1200); 218 | 219 | printtick("Process Sample Start"); 220 | // ProcessNewSamples(audioInputBuffer, SAMPLES_PER_BLOCK); 221 | 222 | ptr = &ADC_Buffer[adc_buffer_mem]; 223 | 224 | for (i = 0; i < SAMPLES_PER_BLOCK; i++) 225 | multi_modem_process_sample (0, *(ptr++)); 226 | 227 | printtick("Process Sample End"); 228 | 229 | adc_buffer_mem = -1; // finished with the ADC buffer that the DMA filled 230 | 231 | // displayLevel(max); 232 | 233 | if (leveltimer++ > 100) 234 | { 235 | leveltimer = 0; 236 | Debugprintf("Input peaks = %d, %d", min, max); 237 | } 238 | min = max = 0; 239 | } 240 | } 241 | 242 | 243 | void StopCapture() 244 | { 245 | Capturing = FALSE; 246 | // printf("Stop Capture\n"); 247 | } 248 | 249 | void StartCodec(char * strFault) 250 | { 251 | strFault[0] = 0; 252 | } 253 | 254 | void StopCodec(char * strFault) 255 | { 256 | strFault[0] = 0; 257 | } 258 | 259 | void StartCapture() 260 | { 261 | Capturing = TRUE; 262 | DiscardOldSamples(); 263 | ClearAllMixedSamples(); 264 | State = SearchingForLeader; 265 | 266 | // printf("Start Capture\n"); 267 | } 268 | void CloseSound() 269 | { 270 | } 271 | 272 | unsigned short * SoundInit() 273 | { 274 | Index = 0; 275 | return &buffer[0][0]; 276 | } 277 | 278 | // Called at end of transmission 279 | 280 | void SoundFlush() 281 | { 282 | // Append Trailer then send remaining samples 283 | 284 | // AddTrailer(); // add the trailer. 285 | 286 | if (Loopback) 287 | { 288 | short loopbuff[1200]; // Temp for testing - loop sent samples to decoder 289 | // ProcessNewSamples(loopbuff, Number); 290 | } 291 | 292 | SendtoCard(buffer[Index], Number * 2); 293 | 294 | // Wait for other DMA buffer to empty beofre shutting down DAC 295 | 296 | while (1) 297 | { 298 | int chan = DMA_GetCurrentMemoryTarget(DMA1_Stream5); 299 | 300 | if (chan == Index) // we've started sending current buffer 301 | { 302 | break; 303 | } 304 | } 305 | 306 | stopDAC(); 307 | DMARunning = FALSE; 308 | 309 | 310 | // I think we should turn round the link here. I dont see the point in 311 | // waiting for MainPoll 312 | 313 | // SoundIsPlaying = FALSE; 314 | 315 | KeyPTT(FALSE); // Unkey the Transmitter 316 | 317 | // StartCapture(); 318 | 319 | return; 320 | } 321 | 322 | // Function to Key radio PTT 323 | 324 | const char BoolString[2][6] = {"FALSE", "TRUE"}; 325 | 326 | BOOL KeyPTT(BOOL blnPTT) 327 | { 328 | // Returns TRUE if successful False otherwise 329 | 330 | SetLED(blnPTT); 331 | return TRUE; 332 | } 333 | 334 | 335 | void audio_put(int a, int b) 336 | { 337 | int work = (short)(b); 338 | DMABuffer[Number++] = (work + 32768) >> 4; // 12 bit left justify 339 | 340 | if (Number == SendSize) 341 | { 342 | // send this buffer to sound interface 343 | 344 | DMABuffer = SendtoCard(DMABuffer, SendSize); 345 | Number = 0; 346 | } 347 | } 348 | 349 | int audio_get(int a) 350 | { 351 | 352 | } 353 | 354 | 355 | 356 | 357 | 358 | 359 | -------------------------------------------------------------------------------- /ardop1ofdm/berlekamp.c: -------------------------------------------------------------------------------- 1 | /*********************************************************************** 2 | * Copyright Henry Minsky (hqm@alum.mit.edu) 1991-2009 3 | * 4 | * This software library is licensed under terms of the GNU GENERAL 5 | * PUBLIC LICENSE 6 | * 7 | * 8 | * RSCODE is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * RSCODE is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with Rscode. If not, see . 20 | * 21 | * Commercial licensing is available under a separate license, please 22 | * contact author for details. 23 | * 24 | * Source code is available at http://rscode.sourceforge.net 25 | * Berlekamp-Peterson and Berlekamp-Massey Algorithms for error-location 26 | * 27 | * From Cain, Clark, "Error-Correction Coding For Digital Communications", pp. 205. 28 | * 29 | * This finds the coefficients of the error locator polynomial. 30 | * 31 | * The roots are then found by looking for the values of a^n 32 | * where evaluating the polynomial yields zero. 33 | * 34 | * Error correction is done using the error-evaluator equation on pp 207. 35 | * 36 | */ 37 | 38 | #include 39 | #include "ecc.h" 40 | 41 | /* The Error Locator Polynomial, also known as Lambda or Sigma. Lambda[0] == 1 */ 42 | static int Lambda[MAXDEG]; 43 | 44 | /* The Error Evaluator Polynomial */ 45 | static int Omega[MAXDEG]; 46 | 47 | /* local ANSI declarations */ 48 | static int compute_discrepancy(int lambda[], int S[], int L, int n); 49 | static void init_gamma(int gamma[]); 50 | static void compute_modified_omega (void); 51 | static void mul_z_poly (int src[]); 52 | 53 | /* error locations found using Chien's search*/ 54 | static int ErrorLocs[256]; 55 | int NErrors; 56 | 57 | extern int MaxErrors; 58 | 59 | /* erasure flags */ 60 | static int ErasureLocs[256]; 61 | static int NErasures; 62 | 63 | /* From Cain, Clark, "Error-Correction Coding For Digital Communications", pp. 216. */ 64 | void 65 | Modified_Berlekamp_Massey (void) 66 | { 67 | int n, L, L2, k, d, i; 68 | int psi[MAXDEG], psi2[MAXDEG], D[MAXDEG]; 69 | int gamma[MAXDEG]; 70 | 71 | /* initialize Gamma, the erasure locator polynomial */ 72 | init_gamma(gamma); 73 | 74 | /* initialize to z */ 75 | copy_poly(D, gamma); 76 | mul_z_poly(D); 77 | 78 | copy_poly(psi, gamma); 79 | k = -1; L = NErasures; 80 | 81 | for (n = NErasures; n < NPAR; n++) { 82 | 83 | d = compute_discrepancy(psi, synBytes, L, n); 84 | 85 | if (d != 0) { 86 | 87 | /* psi2 = psi - d*D */ 88 | for (i = 0; i < NPAR*2; i++) psi2[i] = psi[i] ^ gmult(d, D[i]); 89 | 90 | 91 | if (L < (n-k)) { 92 | L2 = n-k; 93 | k = n-L; 94 | /* D = scale_poly(ginv(d), psi); */ 95 | for (i = 0; i < NPAR*2; i++) D[i] = gmult(psi[i], ginv(d)); 96 | L = L2; 97 | } 98 | 99 | /* psi = psi2 */ 100 | for (i = 0; i < NPAR*2; i++) psi[i] = psi2[i]; 101 | } 102 | 103 | mul_z_poly(D); 104 | } 105 | 106 | for(i = 0; i < NPAR*2; i++) Lambda[i] = psi[i]; 107 | compute_modified_omega(); 108 | 109 | 110 | } 111 | 112 | /* given Psi (called Lambda in Modified_Berlekamp_Massey) and synBytes, 113 | compute the combined erasure/error evaluator polynomial as 114 | Psi*S mod z^4 115 | */ 116 | void 117 | compute_modified_omega () 118 | { 119 | int i; 120 | int product[MAXDEG*2]; 121 | 122 | mult_polys(product, Lambda, synBytes); 123 | zero_poly(Omega); 124 | for(i = 0; i < NPAR; i++) Omega[i] = product[i]; 125 | 126 | } 127 | 128 | /* polynomial multiplication */ 129 | void 130 | mult_polys (int dst[], int p1[], int p2[]) 131 | { 132 | int i, j; 133 | int tmp1[MAXDEG*2]; 134 | 135 | for (i=0; i < (NPAR*2*2); i++) dst[i] = 0; 136 | 137 | for (i = 0; i < NPAR*2; i++) { 138 | for(j=NPAR*2; j<(NPAR*2*2); j++) tmp1[j]=0; 139 | 140 | /* scale tmp1 by p1[i] */ 141 | for(j=0; j= i; j--) tmp1[j] = tmp1[j-i]; 144 | for (j = 0; j < i; j++) tmp1[j] = 0; 145 | 146 | /* add into partial product */ 147 | for(j=0; j < (NPAR*2*2); j++) dst[j] ^= tmp1[j]; 148 | } 149 | } 150 | 151 | 152 | 153 | /* gamma = product (1-z*a^Ij) for erasure locs Ij */ 154 | void 155 | init_gamma (int gamma[]) 156 | { 157 | int e, tmp[MAXDEG]; 158 | 159 | zero_poly(gamma); 160 | zero_poly(tmp); 161 | gamma[0] = 1; 162 | 163 | for (e = 0; e < NErasures; e++) { 164 | copy_poly(tmp, gamma); 165 | scale_poly(gexp[ErasureLocs[e]], tmp); 166 | mul_z_poly(tmp); 167 | add_polys(gamma, tmp); 168 | } 169 | } 170 | 171 | 172 | 173 | void 174 | compute_next_omega (int d, int A[], int dst[], int src[]) 175 | { 176 | int i; 177 | for ( i = 0; i < NPAR*2; i++) { 178 | dst[i] = src[i] ^ gmult(d, A[i]); 179 | } 180 | } 181 | 182 | 183 | 184 | int 185 | compute_discrepancy (int lambda[], int S[], int L, int n) 186 | { 187 | int i, sum=0; 188 | 189 | for (i = 0; i <= L; i++) 190 | sum ^= gmult(lambda[i], S[n-i]); 191 | return (sum); 192 | } 193 | 194 | /********** polynomial arithmetic *******************/ 195 | 196 | void add_polys (int dst[], int src[]) 197 | { 198 | int i; 199 | for (i = 0; i < NPAR*2; i++) dst[i] ^= src[i]; 200 | } 201 | 202 | void copy_poly (int dst[], int src[]) 203 | { 204 | int i; 205 | for (i = 0; i < NPAR*2; i++) dst[i] = src[i]; 206 | } 207 | 208 | void scale_poly (int k, int poly[]) 209 | { 210 | int i; 211 | for (i = 0; i < NPAR*2; i++) poly[i] = gmult(k, poly[i]); 212 | } 213 | 214 | 215 | void zero_poly (int poly[]) 216 | { 217 | int i; 218 | for (i = 0; i < NPAR*2; i++) poly[i] = 0; 219 | } 220 | 221 | 222 | /* multiply by z, i.e., shift right by 1 */ 223 | static void mul_z_poly (int src[]) 224 | { 225 | int i; 226 | for (i = NPAR*2-1; i > 0; i--) src[i] = src[i-1]; 227 | src[0] = 0; 228 | } 229 | 230 | 231 | /* Finds all the roots of an error-locator polynomial with coefficients 232 | * Lambda[j] by evaluating Lambda at successive values of alpha. 233 | * 234 | * This can be tested with the decoder's equations case. 235 | */ 236 | 237 | 238 | void 239 | Find_Roots (void) 240 | { 241 | int sum, r, k; 242 | NErrors = 0; 243 | 244 | for (r = 1; r < 256; r++) { 245 | sum = 0; 246 | /* evaluate lambda at r */ 247 | for (k = 0; k < NPAR+1; k++) { 248 | sum ^= gmult(gexp[(k*r)%255], Lambda[k]); 249 | } 250 | if (sum == 0) 251 | { 252 | ErrorLocs[NErrors] = (255-r); NErrors++; 253 | if (DEBUG) fprintf(stderr, "Root found at r = %d, (255-r) = %d\n", r, (255-r)); 254 | } 255 | } 256 | } 257 | 258 | /* Combined Erasure And Error Magnitude Computation 259 | * 260 | * Pass in the codeword, its size in bytes, as well as 261 | * an array of any known erasure locations, along the number 262 | * of these erasures. 263 | * 264 | * Evaluate Omega(actually Psi)/Lambda' at the roots 265 | * alpha^(-i) for error locs i. 266 | * 267 | * returns 1 if everything ok, or 0 if an out-of-bounds error is found 268 | * 269 | */ 270 | 271 | int 272 | correct_errors_erasures (unsigned char codeword[], 273 | int csize, 274 | int nerasures, 275 | int erasures[]) 276 | { 277 | int r, i, j, err; 278 | 279 | /* If you want to take advantage of erasure correction, be sure to 280 | set NErasures and ErasureLocs[] with the locations of erasures. 281 | */ 282 | NErasures = nerasures; 283 | for (i = 0; i < NErasures; i++) ErasureLocs[i] = erasures[i]; 284 | 285 | Modified_Berlekamp_Massey(); 286 | Find_Roots(); 287 | 288 | 289 | if (DEBUG) fprintf(stderr, "RS found %d errors\n", NErrors); 290 | 291 | 292 | if ((NErrors <= MaxErrors) && NErrors > 0) { 293 | 294 | /* first check for illegal error locs */ 295 | for (r = 0; r < NErrors; r++) { 296 | if (ErrorLocs[r] >= csize) { 297 | if (DEBUG) fprintf(stderr, "Error loc i=%d outside of codeword length %d\n", i, csize); 298 | return(0); 299 | } 300 | } 301 | 302 | for (r = 0; r < NErrors; r++) { 303 | int num, denom; 304 | i = ErrorLocs[r]; 305 | /* evaluate Omega at alpha^(-i) */ 306 | 307 | num = 0; 308 | for (j = 0; j < NPAR*2; j++) 309 | num ^= gmult(Omega[j], gexp[((255-i)*j)%255]); 310 | 311 | /* evaluate Lambda' (derivative) at alpha^(-i) ; all odd powers disappear */ 312 | denom = 0; 313 | for (j = 1; j < NPAR*2; j += 2) { 314 | denom ^= gmult(Lambda[j], gexp[((255-i)*(j-1)) % 255]); 315 | } 316 | 317 | err = gmult(num, ginv(denom)); 318 | if (DEBUG) fprintf(stderr, "Error magnitude %#x at loc %d\n", err, csize-i); 319 | 320 | codeword[csize-i-1] ^= err; 321 | } 322 | return(1); 323 | } 324 | else { 325 | if (DEBUG && NErrors) fprintf(stderr, "Uncorrectable codeword\n"); 326 | return(0); 327 | } 328 | } 329 | 330 | -------------------------------------------------------------------------------- /ardop2ofdm/berlekamp.c: -------------------------------------------------------------------------------- 1 | /*********************************************************************** 2 | * Copyright Henry Minsky (hqm@alum.mit.edu) 1991-2009 3 | * 4 | * This software library is licensed under terms of the GNU GENERAL 5 | * PUBLIC LICENSE 6 | * 7 | * 8 | * RSCODE is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * RSCODE is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with Rscode. If not, see . 20 | * 21 | * Commercial licensing is available under a separate license, please 22 | * contact author for details. 23 | * 24 | * Source code is available at http://rscode.sourceforge.net 25 | * Berlekamp-Peterson and Berlekamp-Massey Algorithms for error-location 26 | * 27 | * From Cain, Clark, "Error-Correction Coding For Digital Communications", pp. 205. 28 | * 29 | * This finds the coefficients of the error locator polynomial. 30 | * 31 | * The roots are then found by looking for the values of a^n 32 | * where evaluating the polynomial yields zero. 33 | * 34 | * Error correction is done using the error-evaluator equation on pp 207. 35 | * 36 | */ 37 | 38 | #include 39 | #include "ecc.h" 40 | 41 | /* The Error Locator Polynomial, also known as Lambda or Sigma. Lambda[0] == 1 */ 42 | static int Lambda[MAXDEG]; 43 | 44 | /* The Error Evaluator Polynomial */ 45 | static int Omega[MAXDEG]; 46 | 47 | /* local ANSI declarations */ 48 | static int compute_discrepancy(int lambda[], int S[], int L, int n); 49 | static void init_gamma(int gamma[]); 50 | static void compute_modified_omega (void); 51 | static void mul_z_poly (int src[]); 52 | 53 | /* error locations found using Chien's search*/ 54 | static int ErrorLocs[256]; 55 | int NErrors; 56 | 57 | extern int MaxErrors; 58 | 59 | /* erasure flags */ 60 | static int ErasureLocs[256]; 61 | static int NErasures; 62 | 63 | /* From Cain, Clark, "Error-Correction Coding For Digital Communications", pp. 216. */ 64 | void 65 | Modified_Berlekamp_Massey (void) 66 | { 67 | int n, L, L2, k, d, i; 68 | int psi[MAXDEG], psi2[MAXDEG], D[MAXDEG]; 69 | int gamma[MAXDEG]; 70 | 71 | /* initialize Gamma, the erasure locator polynomial */ 72 | init_gamma(gamma); 73 | 74 | /* initialize to z */ 75 | copy_poly(D, gamma); 76 | mul_z_poly(D); 77 | 78 | copy_poly(psi, gamma); 79 | k = -1; L = NErasures; 80 | 81 | for (n = NErasures; n < NPAR; n++) { 82 | 83 | d = compute_discrepancy(psi, synBytes, L, n); 84 | 85 | if (d != 0) { 86 | 87 | /* psi2 = psi - d*D */ 88 | for (i = 0; i < NPAR*2; i++) psi2[i] = psi[i] ^ gmult(d, D[i]); 89 | 90 | 91 | if (L < (n-k)) { 92 | L2 = n-k; 93 | k = n-L; 94 | /* D = scale_poly(ginv(d), psi); */ 95 | for (i = 0; i < NPAR*2; i++) D[i] = gmult(psi[i], ginv(d)); 96 | L = L2; 97 | } 98 | 99 | /* psi = psi2 */ 100 | for (i = 0; i < NPAR*2; i++) psi[i] = psi2[i]; 101 | } 102 | 103 | mul_z_poly(D); 104 | } 105 | 106 | for(i = 0; i < NPAR*2; i++) Lambda[i] = psi[i]; 107 | compute_modified_omega(); 108 | 109 | 110 | } 111 | 112 | /* given Psi (called Lambda in Modified_Berlekamp_Massey) and synBytes, 113 | compute the combined erasure/error evaluator polynomial as 114 | Psi*S mod z^4 115 | */ 116 | void 117 | compute_modified_omega () 118 | { 119 | int i; 120 | int product[MAXDEG*2]; 121 | 122 | mult_polys(product, Lambda, synBytes); 123 | zero_poly(Omega); 124 | for(i = 0; i < NPAR; i++) Omega[i] = product[i]; 125 | 126 | } 127 | 128 | /* polynomial multiplication */ 129 | void 130 | mult_polys (int dst[], int p1[], int p2[]) 131 | { 132 | int i, j; 133 | int tmp1[MAXDEG*2]; 134 | 135 | for (i=0; i < (NPAR*2*2); i++) dst[i] = 0; 136 | 137 | for (i = 0; i < NPAR*2; i++) { 138 | for(j=NPAR*2; j<(NPAR*2*2); j++) tmp1[j]=0; 139 | 140 | /* scale tmp1 by p1[i] */ 141 | for(j=0; j= i; j--) tmp1[j] = tmp1[j-i]; 144 | for (j = 0; j < i; j++) tmp1[j] = 0; 145 | 146 | /* add into partial product */ 147 | for(j=0; j < (NPAR*2*2); j++) dst[j] ^= tmp1[j]; 148 | } 149 | } 150 | 151 | 152 | 153 | /* gamma = product (1-z*a^Ij) for erasure locs Ij */ 154 | void 155 | init_gamma (int gamma[]) 156 | { 157 | int e, tmp[MAXDEG]; 158 | 159 | zero_poly(gamma); 160 | zero_poly(tmp); 161 | gamma[0] = 1; 162 | 163 | for (e = 0; e < NErasures; e++) { 164 | copy_poly(tmp, gamma); 165 | scale_poly(gexp[ErasureLocs[e]], tmp); 166 | mul_z_poly(tmp); 167 | add_polys(gamma, tmp); 168 | } 169 | } 170 | 171 | 172 | 173 | void 174 | compute_next_omega (int d, int A[], int dst[], int src[]) 175 | { 176 | int i; 177 | for ( i = 0; i < NPAR*2; i++) { 178 | dst[i] = src[i] ^ gmult(d, A[i]); 179 | } 180 | } 181 | 182 | 183 | 184 | int 185 | compute_discrepancy (int lambda[], int S[], int L, int n) 186 | { 187 | int i, sum=0; 188 | 189 | for (i = 0; i <= L; i++) 190 | sum ^= gmult(lambda[i], S[n-i]); 191 | return (sum); 192 | } 193 | 194 | /********** polynomial arithmetic *******************/ 195 | 196 | void add_polys (int dst[], int src[]) 197 | { 198 | int i; 199 | for (i = 0; i < NPAR*2; i++) dst[i] ^= src[i]; 200 | } 201 | 202 | void copy_poly (int dst[], int src[]) 203 | { 204 | int i; 205 | for (i = 0; i < NPAR*2; i++) dst[i] = src[i]; 206 | } 207 | 208 | void scale_poly (int k, int poly[]) 209 | { 210 | int i; 211 | for (i = 0; i < NPAR*2; i++) poly[i] = gmult(k, poly[i]); 212 | } 213 | 214 | 215 | void zero_poly (int poly[]) 216 | { 217 | int i; 218 | for (i = 0; i < NPAR*2; i++) poly[i] = 0; 219 | } 220 | 221 | 222 | /* multiply by z, i.e., shift right by 1 */ 223 | static void mul_z_poly (int src[]) 224 | { 225 | int i; 226 | for (i = NPAR*2-1; i > 0; i--) src[i] = src[i-1]; 227 | src[0] = 0; 228 | } 229 | 230 | 231 | /* Finds all the roots of an error-locator polynomial with coefficients 232 | * Lambda[j] by evaluating Lambda at successive values of alpha. 233 | * 234 | * This can be tested with the decoder's equations case. 235 | */ 236 | 237 | 238 | void 239 | Find_Roots (void) 240 | { 241 | int sum, r, k; 242 | NErrors = 0; 243 | 244 | for (r = 1; r < 256; r++) { 245 | sum = 0; 246 | /* evaluate lambda at r */ 247 | for (k = 0; k < NPAR+1; k++) { 248 | sum ^= gmult(gexp[(k*r)%255], Lambda[k]); 249 | } 250 | if (sum == 0) 251 | { 252 | ErrorLocs[NErrors] = (255-r); NErrors++; 253 | if (DEBUG) fprintf(stderr, "Root found at r = %d, (255-r) = %d\n", r, (255-r)); 254 | } 255 | } 256 | } 257 | 258 | /* Combined Erasure And Error Magnitude Computation 259 | * 260 | * Pass in the codeword, its size in bytes, as well as 261 | * an array of any known erasure locations, along the number 262 | * of these erasures. 263 | * 264 | * Evaluate Omega(actually Psi)/Lambda' at the roots 265 | * alpha^(-i) for error locs i. 266 | * 267 | * returns 1 if everything ok, or 0 if an out-of-bounds error is found 268 | * 269 | */ 270 | 271 | int 272 | correct_errors_erasures (unsigned char codeword[], 273 | int csize, 274 | int nerasures, 275 | int erasures[]) 276 | { 277 | int r, i, j, err; 278 | 279 | /* If you want to take advantage of erasure correction, be sure to 280 | set NErasures and ErasureLocs[] with the locations of erasures. 281 | */ 282 | NErasures = nerasures; 283 | for (i = 0; i < NErasures; i++) ErasureLocs[i] = erasures[i]; 284 | 285 | Modified_Berlekamp_Massey(); 286 | Find_Roots(); 287 | 288 | 289 | if (DEBUG) fprintf(stderr, "RS found %d errors\n", NErrors); 290 | 291 | 292 | if ((NErrors <= MaxErrors) && NErrors > 0) { 293 | 294 | /* first check for illegal error locs */ 295 | for (r = 0; r < NErrors; r++) { 296 | if (ErrorLocs[r] >= csize) { 297 | if (DEBUG) fprintf(stderr, "Error loc i=%d outside of codeword length %d\n", i, csize); 298 | return(0); 299 | } 300 | } 301 | 302 | for (r = 0; r < NErrors; r++) { 303 | int num, denom; 304 | i = ErrorLocs[r]; 305 | /* evaluate Omega at alpha^(-i) */ 306 | 307 | num = 0; 308 | for (j = 0; j < NPAR*2; j++) 309 | num ^= gmult(Omega[j], gexp[((255-i)*j)%255]); 310 | 311 | /* evaluate Lambda' (derivative) at alpha^(-i) ; all odd powers disappear */ 312 | denom = 0; 313 | for (j = 1; j < NPAR*2; j += 2) { 314 | denom ^= gmult(Lambda[j], gexp[((255-i)*(j-1)) % 255]); 315 | } 316 | 317 | err = gmult(num, ginv(denom)); 318 | if (DEBUG) fprintf(stderr, "Error magnitude %#x at loc %d\n", err, csize-i); 319 | 320 | codeword[csize-i-1] ^= err; 321 | } 322 | return(1); 323 | } 324 | else { 325 | if (DEBUG && NErrors) fprintf(stderr, "Uncorrectable codeword\n"); 326 | return(0); 327 | } 328 | } 329 | 330 | -------------------------------------------------------------------------------- /ardop1ofdm/STM32main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "mbed.h" 3 | #include "ARDOPC.h" 4 | 5 | #include 6 | 7 | #include "stm32f4xx.h" 8 | #include "stm32f4xx_rcc.h" 9 | #include "stm32f4xx_iwdg.h"" 10 | 11 | //AnalogOut my_output(PA_4); 12 | 13 | //short buffer[BUFFER_SIZE]; 14 | 15 | enum kiss_state_e { 16 | KS_SEARCHING, /* Looking for FEND to start KISS frame. */ 17 | KS_COLLECTING}; /* In process of collecting KISS frame. */ 18 | 19 | 20 | #define MAX_KISS_LEN 2048 /* Spec calls for at least 1024. */ 21 | /* Might want to make it longer to accomodate */ 22 | /* maximum packet length. */ 23 | 24 | #define MAX_NOISE_LEN 100 25 | 26 | 27 | typedef struct kiss_frame_s { 28 | 29 | enum kiss_state_e state; 30 | 31 | unsigned char kiss_msg[MAX_KISS_LEN]; 32 | /* Leading FEND is optional. */ 33 | /* Contains escapes and ending FEND. */ 34 | int kiss_len; 35 | 36 | unsigned char noise[MAX_NOISE_LEN]; 37 | int noise_len; 38 | 39 | } kiss_frame_t; 40 | 41 | 42 | 43 | extern "C" { 44 | void InitValidFrameTypes(); 45 | void GetNextFECFrame(); 46 | void direwolfmain(); 47 | void printtick(char * msg); 48 | void Debugprintf(const char * format, ...); 49 | void dw_printf(const char * format, ...); 50 | void Config_ADC_DMA(void); 51 | void Start_ADC_DMA(void); 52 | void ProcessNewSamples(short * Samples, int nSamples); 53 | void CheckTimers(); 54 | void MainPoll(); 55 | void HostPoll(); 56 | //void SetARDOPProtocolState(int State); 57 | 58 | uint32_t DMA_GetCurrentMemoryTarget(DMA_Stream_TypeDef* DMAy_Streamx); 59 | void PollReceivedSamples(); 60 | void SetLED(int blnPTT); 61 | void Sleep(int delay); 62 | void SerialSink(UCHAR c); 63 | void SerialSendData(unsigned char * Msg, int Len); 64 | void PollReceivedSamples(); 65 | 66 | void init_I2C1(void); 67 | void initdisplay(); 68 | void kiss_rec_byte(kiss_frame_t *kf, unsigned char ch, int debug, void (*sendfun)(int,unsigned char*,int)); 69 | // void kiss_rec_byte(kiss_frame_t *kf, unsigned char ch, int debug); 70 | void kiss_send_rec_packet (int chan, unsigned char *fbuf, int flen); 71 | void recv_process(); 72 | int xmit_process(); 73 | } 74 | 75 | 76 | 77 | InterruptIn mybutton(USER_BUTTON); 78 | DigitalOut myled(LED1); 79 | Ticker ti; 80 | 81 | Serial serial(USBTX, USBRX); // Host PTC Emulation 82 | Serial serial3(PC_10, PC_11); // Debug Port 83 | 84 | float delay = 0.001; // 1 mS 85 | 86 | volatile int iTick = 0; 87 | volatile bool bTick = 0; 88 | volatile int iClick = 0; 89 | volatile bool bClick = 0; 90 | volatile int ticks; 91 | volatile int ADCInterrupts = 0; 92 | extern volatile int adc_buffer_mem; 93 | 94 | #define SAMPLES_PER_BLOCK 1200 95 | 96 | int i = 0; 97 | 98 | void SetLED(int blnPTT) 99 | { 100 | myled = blnPTT; 101 | } 102 | 103 | void tick() 104 | { 105 | bTick = true; 106 | ticks++; 107 | } 108 | 109 | void pressed() 110 | { 111 | iClick++; 112 | bClick = true; 113 | } 114 | 115 | 116 | int lastchan = 0; 117 | 118 | 119 | // USB Port is used for SCS Host mode link to host. 120 | 121 | // Must use interrupts (or possibly DMA) as we can't wait while processing sound. 122 | 123 | // HostMode has a maximum frame size of around 262 bytes, and as it is polled 124 | // we only need room for 1 frame 125 | 126 | #define SCSBufferSize 280 127 | #define KISSBufferSize 1024 128 | 129 | char tx_buffer[SCSBufferSize]; 130 | 131 | // Circular buffer pointers 132 | // volatile makes read-modify-write atomic 133 | volatile int tx_in=0; 134 | volatile int tx_out=0; 135 | volatile int tx_stopped = 1; 136 | 137 | unsigned char rx_buffer[KISSBufferSize]; 138 | 139 | // Circular buffer pointers 140 | // volatile makes read-modify-write atomic 141 | volatile int rx_in=0; 142 | volatile int rx_out=0; 143 | 144 | 145 | char line[80]; 146 | 147 | void SerialSendData(unsigned char * Msg, int Len) 148 | { 149 | int i; 150 | i = 0; 151 | 152 | while (i < Len) 153 | { 154 | tx_buffer[tx_in] = Msg[i++]; 155 | tx_in = (tx_in + 1) % SCSBufferSize; 156 | } 157 | 158 | // disable ints to avoid possible race 159 | 160 | // Send first character to start tx interrupts, if stopped 161 | 162 | __disable_irq(); 163 | 164 | if (tx_stopped) 165 | { 166 | serial.putc(tx_buffer[tx_out]); 167 | tx_out = (tx_out + 1) % SCSBufferSize; 168 | tx_stopped = 0; 169 | } 170 | __enable_irq(); 171 | 172 | return; 173 | } 174 | 175 | void rxcallback() 176 | { 177 | // Note: you need to actually read from the serial to clear the RX interrupt 178 | 179 | unsigned char c; 180 | c = serial.getc(); 181 | 182 | rx_buffer[rx_in] = c; 183 | rx_in = (rx_in + 1) % KISSBufferSize; 184 | 185 | } 186 | 187 | void txcallback() 188 | { 189 | // Loop to fill more than one character in UART's transmit FIFO buffer 190 | // Stop if buffer empty 191 | 192 | while ((serial.writeable()) && (tx_in != tx_out)) 193 | { 194 | serial.putc(tx_buffer[tx_out]); 195 | tx_out = (tx_out + 1) % SCSBufferSize; 196 | } 197 | 198 | if (tx_in == tx_out) 199 | tx_stopped = 1; 200 | 201 | return; 202 | } 203 | 204 | // Port 3 is used for debugging 205 | 206 | // Must use interrupts (or possibly DMA) as we can't wait while processing sound. 207 | 208 | // Not sure how big it needs to be. Don't want to use too mach RAM 209 | 210 | #define DebugBufferSize 1024 211 | 212 | char tx3_buffer[DebugBufferSize]; 213 | 214 | // Circular buffer pointers 215 | // volatile makes read-modify-write atomic 216 | volatile int tx3_in=0; 217 | volatile int tx3_out=0; 218 | volatile int tx3_stopped = 1; 219 | 220 | 221 | void Serial3SendData(unsigned char * Msg, int Len) 222 | { 223 | int i; 224 | i = 0; 225 | 226 | while (i < Len) 227 | { 228 | tx3_buffer[tx3_in] = Msg[i++]; 229 | tx3_in = (tx3_in + 1) % DebugBufferSize; 230 | } 231 | 232 | // disable ints to avoid possible race 233 | 234 | // Send first character to start tx interrupts, if stopped 235 | 236 | __disable_irq(); 237 | 238 | if (tx3_stopped) 239 | { 240 | serial3.putc(tx3_buffer[tx3_out]); 241 | tx3_out = (tx3_out + 1) % DebugBufferSize; 242 | tx3_stopped = 0; 243 | } 244 | __enable_irq(); 245 | 246 | return; 247 | } 248 | 249 | void rx3callback() 250 | { 251 | // Note: you need to actually read from the serial to clear the RX interrupt 252 | 253 | unsigned char c; 254 | 255 | c = serial3.getc(); 256 | 257 | // SerialSink(c); 258 | // serial2.printf("%c", c); 259 | 260 | // myled = !myled; 261 | } 262 | 263 | void tx3callback() 264 | { 265 | // Loop to fill more than one character in UART's transmit FIFO buffer 266 | // Stop if buffer empty 267 | 268 | while ((serial3.writeable()) && (tx3_in != tx3_out)) 269 | { 270 | serial3.putc(tx3_buffer[tx3_out]); 271 | tx3_out = (tx3_out + 1) % DebugBufferSize; 272 | } 273 | 274 | if (tx3_in == tx3_out) 275 | tx3_stopped = 1; 276 | 277 | return; 278 | } 279 | 280 | 281 | extern kiss_frame_t kf; /* Accumulated KISS frame and state of decoder. */ 282 | 283 | int kissdebug = 2; 284 | 285 | int main() 286 | { 287 | serial.baud(115200); 288 | serial3.baud(115200); 289 | 290 | serial.attach(&rxcallback); 291 | serial.attach(&txcallback, Serial::TxIrq); 292 | 293 | // serial3.attach(&rxc3allback); 294 | serial3.attach(&tx3callback, Serial::TxIrq); 295 | 296 | /* Check if the system has resumed from WWDG reset */ 297 | 298 | if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET) 299 | { 300 | Debugprintf("Reset by watchdog"); 301 | RCC_ClearFlag(); 302 | } 303 | 304 | /* Enable write access to IWDG_PR and IWDG_RLR registers */ 305 | IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); 306 | 307 | /* IWDG counter clock: LSI/256, ~6.4ms */ 308 | IWDG_SetPrescaler(IWDG_Prescaler_256); 309 | 310 | IWDG_SetReload(2000); // ~12 secs 311 | 312 | /* Reload IWDG counter */ 313 | IWDG_ReloadCounter(); 314 | 315 | /* Enable IWDG (the LSI oscillator will be enabled by hardware) */ 316 | // IWDG_Enable(); 317 | 318 | 319 | Debugprintf("Clock Freq %d", SystemCoreClock); 320 | 321 | // init_I2C1(); 322 | 323 | Debugprintf("i2c init returned"); 324 | 325 | // initdisplay(); 326 | 327 | mybutton.fall(&pressed); 328 | 329 | ti.attach(tick, .001); 330 | 331 | direwolfmain(); 332 | 333 | myled = 0; 334 | 335 | while (1) 336 | { 337 | unsigned char ch; 338 | 339 | if (rx_in != rx_out) 340 | { 341 | ch = rx_buffer[rx_out]; 342 | rx_out = (rx_out + 1) % KISSBufferSize; 343 | kiss_rec_byte (&kf, ch, kissdebug, kiss_send_rec_packet); 344 | } 345 | 346 | PollReceivedSamples(); 347 | 348 | recv_process(); 349 | 350 | // See if we have anything to send 351 | 352 | xmit_process(); 353 | } 354 | } 355 | 356 | 357 | extern "C" void PlatformSleep() 358 | { 359 | // Called at end of main loop 360 | 361 | IWDG_ReloadCounter(); 362 | 363 | if (bTick) 364 | { 365 | // serial.printf("ADCInterrupts %i %d %d buffer no %d \r\n", ADCInterrupts, 366 | // ADC_Buffer[0][0], ADC_Buffer[1][0], DMA_GetCurrentMemoryTarget(DMA2_Stream0)); 367 | 368 | bTick = false; 369 | } 370 | 371 | if (bClick) 372 | { 373 | bClick = false; 374 | } 375 | 376 | myled = !myled; 377 | 378 | wait(delay); 379 | } 380 | 381 | void Sleep(int delay) 382 | { 383 | wait(delay/1000); 384 | return; 385 | } 386 | 387 | VOID Debugprintf(const char * format, ...) 388 | { 389 | char Mess[1000]; 390 | va_list(arglist); 391 | 392 | va_start(arglist, format); 393 | vsprintf(Mess, format, arglist); 394 | strcat(Mess, "\r\n"); 395 | 396 | Serial3SendData((unsigned char *)Mess, strlen(Mess)); 397 | 398 | return; 399 | } 400 | 401 | VOID dw_printf(const char * format, ...) 402 | { 403 | char Mess[1000]; 404 | va_list(arglist); 405 | 406 | va_start(arglist, format); 407 | vsprintf(Mess, format, arglist); 408 | 409 | Serial3SendData((unsigned char *)Mess, strlen(Mess)); 410 | 411 | return; 412 | } 413 | 414 | 415 | 416 | 417 | 418 | 419 | -------------------------------------------------------------------------------- /ardop1ofdm/SerialIntefaceSpec.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | ARDOP Serial Interface Protocol. 17 | 18 | 19 | 20 |

ARDOP Serial Interface Protocol.

21 | 22 |

Overview.

23 |

24 | The Host to TNC protocol used over Serisl and Bluetooth links operates in two modes, Text or Hostmode. 25 | Text mode is primarily used for initialisation and testing, but can be used for simple interative 26 | QSO's using a standard ASCII terminal program. There is no error checking on the text interface. 27 | Hostmode is used for automatic operation, and provides error detection and recovery over the 28 | serial/Bluetooth line. ARDOP Hostmode is based on the SCS CRC Hostmode (as used in 29 | the PTC and Dragon Controllers) which is itself an extension of WA8DED Hostmode. 30 | 31 |

Operating Modes.

32 |

33 | Either Protocol Mode can be used on one of two Operating Modes. ARDOP Native or PTC Emulation. 34 | The former supports the full ARDOP functionality, the latter enables ARDOP to be used with programs 35 | that support an SCS Pactor controllet, but don't have native ARDOP support. 36 | 37 |

ARDOP Native Mode.

38 |

39 | ARDOP Native Mode is designed to be functionally similar to the TCP mode, to simplify host 40 | program and TNC support. Two DED Channels are assigned to the functions of the two TCP ports, 41 | Channel 32 for Control and Channel 33 for Data. A third channel (34) is used for debug information, 42 | as a standalone TNC doesn't usually have local storage for writing a debug log. The Protocol control channels 43 | (255 for polling, 254 for status and 253 for rig control) are used as defined by SCS. 44 | 45 |

PTC Emulation Mode.

46 |

47 | This supports basic ARQ mode operation with software designed for Pactor. FEC operation isn't 48 | supported, but the Pactor Levels 1-4 are mapped to the ARDOP Bandwidths of 200 to 2000. Pactor 49 | Host Mode commands are converted to equivalent ARDOP commands, and ARDOP link status values mapped 50 | to equivalent Pactor values. 51 | 52 |

Protocol Overview

53 |

54 | The protocol is polled master/slave, with a single bit sequence toggle to detect lost or duplicated frames. 55 | The host program is the master and the TNC the slave. The polling frequency isn't defined, but a maximum interval of 100mS is recommended to minimise latency. 56 |

57 | The link is considered Idle when the master has received an in-sequence response to its previous transmission. 58 | The master can transmit at any time the link is idle. If it has data to send, it sends it, otherwise it sends a 59 | General Poll message. The slave will respond with a list (possibly empty) of channels with data available. The master then polls each channel in the list. 60 |

61 | If the master doesn't receive a valid response from the slave in a resonable time, it will repeat its last transmission. It it doesn't get a reponse after a reasonable number of retries it will report a link failure to 62 | the higher lovel software, which will abort any transmission n progess, then try to reestablish the link. 63 |
64 |
65 | If the master receives an out of sequence response following a timeout and retry it will assume a delayed response 66 | from the slave, discard the respeat, and continue to wait for a valid frame. If it receives an out of sequence response at any other time it will assume a protocol error and reset and restart the link. 67 |
68 |
69 | If the slave receives an out of sequence message it will assume that its previous response was lost, discard the message and resend the previous response unchanged. 70 | 71 | 72 | 73 |

Packet Formats

74 | 75 |
 76 |  
 77 |  All packets have a two byte header of 0xAAAA and a two byte CRC-16 checksum on end
 78 |  The top bit of the Opcode field is a sequence toggle.
 79 |  
 80 |  The basic packet format is:
 81 |  -----------------------------------------------
 82 |  |Header|Chan|Opcode| Payload          | CRC |
 83 |  -----------------------------------------------
 84 |  |AA AA | XX |  XX  | XX XX XX .... XX |XX XX|
 85 |  -----------------------------------------------
 86 |  
 87 |  Payload can have two formats, either a Null terminated ASCII string or a Byte Count of
 88 |  0 to 255 followed by 1 to 256 bytes of data. 
 89 |  
 90 |  There are two opcodes for Host to TNC packets, and eight for TNC to Host, though not
 91 |  all are used in ARDOP Native Mode.
 92 |  
 93 |  From Host to TNC
 94 |  
 95 |  Opcode 0 - Data
 96 |  Opcode 1 - Command
 97 |  
 98 |  From TNC to Host
 99 |  
100 |  Opcode 0 - Response Success (no data follows)
101 |  Opcode 1 - Response Success, followed by null terminated message
102 |  Opcode 2 - Response Failure, followed by null terminated message
103 |  Opcode 7 - Data, preceeded by (length-1)
104 |  
105 |  Channel 32 is used for Commands, Channel 33 for Data and Channel 34 for Debug information. Typical messages 
106 |  are shown below (control fields in Hex). Note that the Command format is used for hostmode 
107 |  protocol level commands. ARDOP commands (such as "ARQCALL") are sent as data on the 
108 |  Command channel. The Debug channel is for information to be written to a debug log.
109 |  
110 |  General Poll
111 |  
112 |  ----------------------------------
113 |  |Header|Chan|Opcode|Payload| CRC |
114 |  ----------------------------------
115 |  |AA AA | FF |  01  | 00 47 |XX XX|
116 |  ----------------------------------
117 |  
118 |  Response is a null terminated list of channels with available data. Value is Channel plus 1
119 |  
120 | ----------------------------------
121 |  |AA AA | FF |  01  | 21 00 |XX XX|            Channel 32 has data (0x21 = 32 + 1)
122 |  ----------------------------------
123 |   
124 |  Poll to TNC Command Channel
125 |  
126 |  ----------------------------------
127 |  |Header|Chan|Opcode|Payload| CRC |
128 |  ----------------------------------
129 |  |AA AA | 20 |  01  | 00 47 |XX XX|
130 |  ----------------------------------
131 |  
132 |  Response is an async ARDOP response message
133 |  
134 |  --------------------------------------------------
135 |  |Header|Chan|Opcode| Payload               | CRC |
136 |  --------------------------------------------------
137 |  |AA AA | 20 |  07  |<0F>c:NEWSTATE ISS <0D>|XX XX|
138 |  --------------------------------------------------
139 |  
140 | 
141 |  ARDOP Command to TNC
142 |  -----------------------------------------------------
143 |  |Header|Chan|Opcode| Payload                  | CRC |
144 |  -----------------------------------------------------
145 |  |AA AA | 20 |  00  |C:MYCALL G8BPQ <00>       |XX XX|
146 |  ----------------------------------------------------
147 |  response
148 |  -----------------------------------------------------
149 |  |AA AA | 20 |  01  |c:MYCALL now G8BPQ <00>   |XX XX|
150 |  -----------------------------------------------------
151 |  
152 |  Data to be transmitted
153 |  -----------------------------------------------------
154 |  |Header|Chan|Opcode| Payload                  | CRC |
155 |  -----------------------------------------------------
156 |  |AA AA | 21 |  00  |<12>D:(Len)Message to Send|XX XX|
157 |  -----------------------------------------------------
158 |  response
159 |  -----------------------------------------------------
160 |  |AA AA | 21 |  00 |                           |XX XX|
161 |  -----------------------------------------------------
162 |  
163 |  Received Data from TNC
164 |  
165 |  Data to be transmitted
166 |  -----------------------------------------------------
167 |  |Header|Chan|Opcode| Payload                  | CRC |
168 |  -----------------------------------------------------
169 |  |AA AA | 21 |  07  |<13>d:(Len)ARQMsg Received|XX XX|
170 |  -----------------------------------------------------
171 |  This is no response to inbound frames, apart from the implied ACK of the
172 |  next host frame having an inverted toggle.
173 |  
174 |  
175 |  
176 | 177 |

Appendix

178 |

179 | SCS CRC Hostmode

180 | 181 | See the PTC-IIIusb Manual Chapter 10 for details of CRC Hostmode .

182 | 183 | WA8DED Packet Format

184 | 185 | There are two data formats, null terminted or counted. 186 | 187 |

188 |  
189 |  Byte 0		Channel Number
190 |  byte 1		Type Code (see table below)
191 |  byte 3-end	Null Terminated string (max length 255)
192 |  or
193 |  byte 3		Info Length - 1
194 |  byte 4-end Info (length 1 to 256)
195 | 
196 | SCS CRC Hostmode adds two byte of 170 to the front and a crc-16 checksum to the end.
197 | It also defines the top bit (bit 7) of the Type Code as a sequence toggle and next bit
198 | (bit 6) as a sequence reset flag. Data transparency is ensured by adding a null byte
199 | after any occurence of 170 in the message or crc. 
200 | 
201 | Command Codes
202 | 
203 | 		  Host to Tnc
204 |           -----------
205 |  CHANNEL   CODE           DESCRIPTION
206 |  -------   ----           -----------
207 |     n       0        Information (preceeded by length-1)
208 |     n       1        Command     (preceeded by length-1)
209 | 
210 |           Tnc to Host
211 |           -----------
212 |  CHANNEL   CODE           DESCRIPTION
213 |  -------   ----           -----------
214 |     n       0        Success (nothing follows)
215 |     n       1        Success (message follows, null terminated)
216 |     n       2        Failure (message follows, null terminated)
217 |     n       3        Link Status (null terminated)
218 |     n       4        Monitor Header (null terminated)
219 |     n       5        Monitor Header (null terminated)
220 |     n       6        Monitor Information (preceeded by length-1)
221 |     n       7        Connect Information (preceeded by length-1)
222 | 
223 | -------------------------------------------------------------------------------- /ardop2ofdm/SerialIntefaceSpec.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | ARDOP Serial Interface Protocol. 17 | 18 | 19 | 20 |

ARDOP Serial Interface Protocol.

21 | 22 |

Overview.

23 |

24 | The Host to TNC protocol used over Serisl and Bluetooth links operates in two modes, Text or Hostmode. 25 | Text mode is primarily used for initialisation and testing, but can be used for simple interative 26 | QSO's using a standard ASCII terminal program. There is no error checking on the text interface. 27 | Hostmode is used for automatic operation, and provides error detection and recovery over the 28 | serial/Bluetooth line. ARDOP Hostmode is based on the SCS CRC Hostmode (as used in 29 | the PTC and Dragon Controllers) which is itself an extension of WA8DED Hostmode. 30 | 31 |

Operating Modes.

32 |

33 | Either Protocol Mode can be used on one of two Operating Modes. ARDOP Native or PTC Emulation. 34 | The former supports the full ARDOP functionality, the latter enables ARDOP to be used with programs 35 | that support an SCS Pactor controllet, but don't have native ARDOP support. 36 | 37 |

ARDOP Native Mode.

38 |

39 | ARDOP Native Mode is designed to be functionally similar to the TCP mode, to simplify host 40 | program and TNC support. Two DED Channels are assigned to the functions of the two TCP ports, 41 | Channel 32 for Control and Channel 33 for Data. A third channel (34) is used for debug information, 42 | as a standalone TNC doesn't usually have local storage for writing a debug log. The Protocol control channels 43 | (255 for polling, 254 for status and 253 for rig control) are used as defined by SCS. 44 | 45 |

PTC Emulation Mode.

46 |

47 | This supports basic ARQ mode operation with software designed for Pactor. FEC operation isn't 48 | supported, but the Pactor Levels 1-4 are mapped to the ARDOP Bandwidths of 200 to 2000. Pactor 49 | Host Mode commands are converted to equivalent ARDOP commands, and ARDOP link status values mapped 50 | to equivalent Pactor values. 51 | 52 |

Protocol Overview

53 |

54 | The protocol is polled master/slave, with a single bit sequence toggle to detect lost or duplicated frames. 55 | The host program is the master and the TNC the slave. The polling frequency isn't defined, but a maximum interval of 100mS is recommended to minimise latency. 56 |

57 | The link is considered Idle when the master has received an in-sequence response to its previous transmission. 58 | The master can transmit at any time the link is idle. If it has data to send, it sends it, otherwise it sends a 59 | General Poll message. The slave will respond with a list (possibly empty) of channels with data available. The master then polls each channel in the list. 60 |

61 | If the master doesn't receive a valid response from the slave in a resonable time, it will repeat its last transmission. It it doesn't get a reponse after a reasonable number of retries it will report a link failure to 62 | the higher lovel software, which will abort any transmission n progess, then try to reestablish the link. 63 |
64 |
65 | If the master receives an out of sequence response following a timeout and retry it will assume a delayed response 66 | from the slave, discard the respeat, and continue to wait for a valid frame. If it receives an out of sequence response at any other time it will assume a protocol error and reset and restart the link. 67 |
68 |
69 | If the slave receives an out of sequence message it will assume that its previous response was lost, discard the message and resend the previous response unchanged. 70 | 71 | 72 | 73 |

Packet Formats

74 | 75 |
 76 |  
 77 |  All packets have a two byte header of 0xAAAA and a two byte CRC-16 checksum on end
 78 |  The top bit of the Opcode field is a sequence toggle.
 79 |  
 80 |  The basic packet format is:
 81 |  -----------------------------------------------
 82 |  |Header|Chan|Opcode| Payload          | CRC |
 83 |  -----------------------------------------------
 84 |  |AA AA | XX |  XX  | XX XX XX .... XX |XX XX|
 85 |  -----------------------------------------------
 86 |  
 87 |  Payload can have two formats, either a Null terminated ASCII string or a Byte Count of
 88 |  0 to 255 followed by 1 to 256 bytes of data. 
 89 |  
 90 |  There are two opcodes for Host to TNC packets, and eight for TNC to Host, though not
 91 |  all are used in ARDOP Native Mode.
 92 |  
 93 |  From Host to TNC
 94 |  
 95 |  Opcode 0 - Data
 96 |  Opcode 1 - Command
 97 |  
 98 |  From TNC to Host
 99 |  
100 |  Opcode 0 - Response Success (no data follows)
101 |  Opcode 1 - Response Success, followed by null terminated message
102 |  Opcode 2 - Response Failure, followed by null terminated message
103 |  Opcode 7 - Data, preceeded by (length-1)
104 |  
105 |  Channel 32 is used for Commands, Channel 33 for Data and Channel 34 for Debug information. Typical messages 
106 |  are shown below (control fields in Hex). Note that the Command format is used for hostmode 
107 |  protocol level commands. ARDOP commands (such as "ARQCALL") are sent as data on the 
108 |  Command channel. The Debug channel is for information to be written to a debug log.
109 |  
110 |  General Poll
111 |  
112 |  ----------------------------------
113 |  |Header|Chan|Opcode|Payload| CRC |
114 |  ----------------------------------
115 |  |AA AA | FF |  01  | 00 47 |XX XX|
116 |  ----------------------------------
117 |  
118 |  Response is a null terminated list of channels with available data. Value is Channel plus 1
119 |  
120 | ----------------------------------
121 |  |AA AA | FF |  01  | 21 00 |XX XX|            Channel 32 has data (0x21 = 32 + 1)
122 |  ----------------------------------
123 |   
124 |  Poll to TNC Command Channel
125 |  
126 |  ----------------------------------
127 |  |Header|Chan|Opcode|Payload| CRC |
128 |  ----------------------------------
129 |  |AA AA | 20 |  01  | 00 47 |XX XX|
130 |  ----------------------------------
131 |  
132 |  Response is an async ARDOP response message
133 |  
134 |  --------------------------------------------------
135 |  |Header|Chan|Opcode| Payload               | CRC |
136 |  --------------------------------------------------
137 |  |AA AA | 20 |  07  |<0F>c:NEWSTATE ISS <0D>|XX XX|
138 |  --------------------------------------------------
139 |  
140 | 
141 |  ARDOP Command to TNC
142 |  -----------------------------------------------------
143 |  |Header|Chan|Opcode| Payload                  | CRC |
144 |  -----------------------------------------------------
145 |  |AA AA | 20 |  00  |C:MYCALL G8BPQ <00>       |XX XX|
146 |  ----------------------------------------------------
147 |  response
148 |  -----------------------------------------------------
149 |  |AA AA | 20 |  01  |c:MYCALL now G8BPQ <00>   |XX XX|
150 |  -----------------------------------------------------
151 |  
152 |  Data to be transmitted
153 |  -----------------------------------------------------
154 |  |Header|Chan|Opcode| Payload                  | CRC |
155 |  -----------------------------------------------------
156 |  |AA AA | 21 |  00  |<12>D:(Len)Message to Send|XX XX|
157 |  -----------------------------------------------------
158 |  response
159 |  -----------------------------------------------------
160 |  |AA AA | 21 |  00 |                           |XX XX|
161 |  -----------------------------------------------------
162 |  
163 |  Received Data from TNC
164 |  
165 |  Data to be transmitted
166 |  -----------------------------------------------------
167 |  |Header|Chan|Opcode| Payload                  | CRC |
168 |  -----------------------------------------------------
169 |  |AA AA | 21 |  07  |<13>d:(Len)ARQMsg Received|XX XX|
170 |  -----------------------------------------------------
171 |  This is no response to inbound frames, apart from the implied ACK of the
172 |  next host frame having an inverted toggle.
173 |  
174 |  
175 |  
176 | 177 |

Appendix

178 |

179 | SCS CRC Hostmode

180 | 181 | See the PTC-IIIusb Manual Chapter 10 for details of CRC Hostmode .

182 | 183 | WA8DED Packet Format

184 | 185 | There are two data formats, null terminted or counted. 186 | 187 |

188 |  
189 |  Byte 0		Channel Number
190 |  byte 1		Type Code (see table below)
191 |  byte 3-end	Null Terminated string (max length 255)
192 |  or
193 |  byte 3		Info Length - 1
194 |  byte 4-end Info (length 1 to 256)
195 | 
196 | SCS CRC Hostmode adds two byte of 170 to the front and a crc-16 checksum to the end.
197 | It also defines the top bit (bit 7) of the Type Code as a sequence toggle and next bit
198 | (bit 6) as a sequence reset flag. Data transparency is ensured by adding a null byte
199 | after any occurence of 170 in the message or crc. 
200 | 
201 | Command Codes
202 | 
203 | 		  Host to Tnc
204 |           -----------
205 |  CHANNEL   CODE           DESCRIPTION
206 |  -------   ----           -----------
207 |     n       0        Information (preceeded by length-1)
208 |     n       1        Command     (preceeded by length-1)
209 | 
210 |           Tnc to Host
211 |           -----------
212 |  CHANNEL   CODE           DESCRIPTION
213 |  -------   ----           -----------
214 |     n       0        Success (nothing follows)
215 |     n       1        Success (message follows, null terminated)
216 |     n       2        Failure (message follows, null terminated)
217 |     n       3        Link Status (null terminated)
218 |     n       4        Monitor Header (null terminated)
219 |     n       5        Monitor Header (null terminated)
220 |     n       6        Monitor Information (preceeded by length-1)
221 |     n       7        Connect Information (preceeded by length-1)
222 | 
223 | -------------------------------------------------------------------------------- /ardop1ofdm/Nucleo_i2c.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "stm32f4xx_gpio.h" 4 | #include 5 | 6 | #include "ARDOPC.h" 7 | 8 | /* setup SCL and SDA pins 9 | * You can connect I2C1 to two different 10 | * pairs of pins: 11 | * 1. SCL on PB6 and SDA on PB7 12 | * 2. SCL on PB8 and SDA on PB9 13 | */ 14 | 15 | void init_I2C1(void){ 16 | 17 | GPIO_InitTypeDef GPIO_InitStruct; 18 | I2C_InitTypeDef I2C_InitStruct; 19 | 20 | // enable APB1 peripheral clock for I2C1 21 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); 22 | // enable clock for SCL and SDA pins 23 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); 24 | 25 | GPIO_StructInit(&GPIO_InitStruct); 26 | GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; // PB8 and PB9 27 | GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // set pins to alternate function 28 | GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // set GPIO speed 29 | GPIO_InitStruct.GPIO_OType = GPIO_OType_OD; // set output to open drain --> the line has to be only pulled low, not driven high | 30 | GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; // enable pull up resistors <---------------------<-------------------------------<| 31 | GPIO_Init(GPIOB, &GPIO_InitStruct); // init GPIOB 32 | 33 | // Connect I2C1 pins to AF 34 | GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_I2C1); // SCL 35 | GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1); // SDA 36 | 37 | // configure I2C1 38 | I2C_StructInit(&I2C_InitStruct); 39 | I2C_InitStruct.I2C_ClockSpeed = 100000; // 100kHz(standard) vs 400 40 | I2C_InitStruct.I2C_Mode = I2C_Mode_I2C; // I2C mode 41 | I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; // 50% duty cycle --> standard 42 | I2C_InitStruct.I2C_OwnAddress1 = 0x00; // own address, not relevant in master mode 43 | I2C_InitStruct.I2C_Ack = I2C_Ack_Disable; // disable acknowledge when reading (can be changed later on) 44 | I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // set address length to 7 bit addresses 45 | I2C_Init(I2C1, &I2C_InitStruct); // init I2C1 46 | 47 | // enable I2C1 48 | I2C_Cmd(I2C1, ENABLE); //sets PE bit in CR1, at end` 49 | } 50 | /* This function issues a start condition and2 51 | * transmits the slave address + R/W bit 52 | * 53 | * Parameters: 54 | * I2Cx --> the I2C peripheral e.g. I2C1 55 | * address --> the 7 bit slave address 56 | * direction --> the tranmission direction can be: 57 | * I2C_Direction_Tranmitter for Master transmitter mode 58 | * I2C_Direction_Receiver for Master receiver 59 | */ 60 | void I2C_start(I2C_TypeDef* I2Cx, uint8_t address, uint8_t direction){ 61 | // wait until I2C1 is not busy anymore 62 | 63 | while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY)); 64 | 65 | // Send I2C1 START condition 66 | I2C_GenerateSTART(I2Cx, ENABLE); 67 | 68 | // wait for I2C1 EV5 --> Slave has acknowledged start condition 69 | while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT)); 70 | 71 | // Send slave Address for write 72 | I2C_Send7bitAddress(I2Cx, address, direction); 73 | 74 | /* wait for I2C1 EV6, check if 75 | * either Slave has acknowledged Master transmitter or 76 | * Master receiver mode, depending on the transmission 77 | * direction 78 | */ 79 | if(direction == I2C_Direction_Transmitter){ 80 | while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); 81 | } 82 | else if(direction == I2C_Direction_Receiver){ 83 | while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); 84 | } 85 | } 86 | 87 | /* This function transmits one byte to the slave device 88 | * Parameters: 89 | * I2Cx --> the I2C peripheral e.g. I2C1 90 | * data --> the data byte to be transmitted 91 | */ 92 | void I2C_write(I2C_TypeDef* I2Cx, uint8_t data){ 93 | I2C_SendData(I2Cx, data); 94 | // wait for I2C1 EV8_2 --> byte has been transmitted 95 | while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); 96 | } 97 | 98 | /* This function reads one byte from the slave device 99 | * and acknowledges the byte (requests another byte) 100 | */ 101 | uint8_t I2C_read_ack(I2C_TypeDef* I2Cx){ 102 | // enable acknowledge of recieved data 103 | I2C_AcknowledgeConfig(I2Cx, ENABLE); 104 | // wait until one byte has been received 105 | while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) ); 106 | // read data from I2C data register and return data byte 107 | uint8_t data = I2C_ReceiveData(I2Cx); 108 | return data; 109 | } 110 | 111 | /* This function reads one byte from the slave device 112 | * and doesn't acknowledge the recieved data 113 | */ 114 | uint8_t I2C_read_nack(I2C_TypeDef* I2Cx){ 115 | // disabe acknowledge of received data 116 | I2C_AcknowledgeConfig(I2Cx, DISABLE); 117 | // wait until one byte has been received 118 | while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) ); 119 | // read data from I2C data register and return data byte 120 | uint8_t data = I2C_ReceiveData(I2Cx); 121 | return data; 122 | } 123 | 124 | /* This funtion issues a stop condition and therefore 125 | * releases the bus 126 | */ 127 | void I2C_stop(I2C_TypeDef* I2Cx){ 128 | // Send I2C1 STOP Condition 129 | I2C_GenerateSTOP(I2Cx, ENABLE); 130 | } 131 | 132 | 133 | // Display Interface 134 | 135 | unsigned short i2c_ADDR = 0x4E; // Display address 136 | 137 | // COMMANDOS 138 | #define LCD_CLEARDISPLAY 0x01 139 | #define LCD_RETURNHOME 0x02 140 | #define LCD_ENTRYMODESET 0x04 141 | #define LCD_DISPLAYCONTROL 0x08 142 | #define LCD_CURSORSHIFT 0x10 143 | #define LCD_FUNCTIONSET 0x20 144 | #define LCD_SETCGRAMADDR 0x40 145 | #define LCD_SETDDRAMADDR 0x80 146 | #define LCD_BACKLIGHT 0x08 147 | #define LCD_NOBACKLIGHT 0x00 148 | 149 | // FLAGS PARA EL MODO DE ENTRADA 150 | #define LCD_ENTRYRIGHT 0x00 151 | #define LCD_ENTRYLEFT 0x02 152 | #define LCD_ENTRYSHIFTINCREMENT 0x01 153 | #define LCD_ENTRYSHIFTDECREMENT 0x00 154 | 155 | // FLAGS DE DISPLAY CONTROL 156 | #define LCD_DISPLAYON 0x04 157 | #define LCD_DISPLAYOFF 0x00 158 | #define LCD_CURSORON 0x02 159 | #define LCD_CURSOROFF 0x00 160 | #define LCD_BLINKON 0x01 161 | #define LCD_BLINKOFF 0x00 162 | 163 | // FLAGS DE FUNCTION SET 164 | #define LCD_8BITMODE 0x10 165 | #define LCD_4BITMODE 0x00 166 | #define LCD_2LINE 0x08 167 | #define LCD_1LINE 0x00 168 | #define LCD_5x10DOTS 0x04 169 | #define LCD_5x8DOTS 0x00 170 | 171 | 172 | #define LCD_EN 0x04 // Enable bit 173 | #define LCD_RW 0x02 // Read/Write bit 174 | #define LCD_RS 0x01 // Register select bit 175 | 176 | 177 | 178 | void clear(int i2cfile); 179 | void home(int i2cfile); 180 | void locate(int i2cfile, int row, int col); 181 | void print(int i2cfile, const char *text); 182 | int initialize(const char *i2c_device, int addr); 183 | void finalize(int i2cfile); 184 | 185 | //#include 186 | 187 | int i2cfile; 188 | 189 | void usleep(float usec) 190 | { 191 | wait(usec/1000000); 192 | } 193 | 194 | 195 | void expanderWrite(int i2cfile, char value) 196 | { 197 | char buffer = value | LCD_BACKLIGHT; 198 | 199 | I2C_start(I2C1, i2c_ADDR, I2C_Direction_Transmitter); 200 | I2C_write(I2C1, buffer); 201 | I2C_stop(I2C1); 202 | } 203 | 204 | void pulseEnable(int i2cfile, char value) 205 | { 206 | expanderWrite(i2cfile, value | LCD_EN); 207 | // usleep(1); 208 | 209 | expanderWrite(i2cfile, value & ~LCD_EN); 210 | // usleep(50); 211 | } 212 | 213 | void write4bits(int i2cfile, char value) 214 | { 215 | expanderWrite(i2cfile, value); 216 | pulseEnable(i2cfile, value); 217 | } 218 | 219 | void i2csend(int i2cfile, char value, char mode) 220 | { 221 | char h = value & 0xf0; 222 | char l = (value << 4) & 0xf0; 223 | write4bits(i2cfile, h | mode); 224 | write4bits(i2cfile, l | mode); 225 | } 226 | 227 | void command(int i2cfile, char value) 228 | { 229 | i2csend(i2cfile, value, 0); 230 | } 231 | 232 | int initialize(const char *i2c_device, int addr) 233 | { 234 | expanderWrite(i2cfile, LCD_BACKLIGHT); 235 | 236 | write4bits(i2cfile, 0x03 << 4); 237 | 238 | write4bits(i2cfile, 0x30); 239 | // usleep(4500); 240 | write4bits(i2cfile, 0x30); 241 | // usleep(150); 242 | 243 | write4bits(i2cfile, 0x20); 244 | 245 | // Set 2 Lines 246 | 247 | command(i2cfile, LCD_FUNCTIONSET | LCD_2LINE); 248 | command(i2cfile, LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF); 249 | clear(i2cfile); 250 | command(i2cfile, LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT); 251 | home(i2cfile); 252 | 253 | return i2cfile; 254 | } 255 | 256 | void finalize(int i2cfile) 257 | { 258 | } 259 | 260 | void clear(int i2cfile) 261 | { 262 | command(i2cfile, LCD_CLEARDISPLAY); 263 | } 264 | 265 | void home(int i2cfile) 266 | { 267 | command(i2cfile, LCD_RETURNHOME); 268 | } 269 | 270 | void locate(int i2cfile, int row, int col) 271 | { 272 | static int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; 273 | command(i2cfile, LCD_SETDDRAMADDR | ((col % 16) + row_offsets[row % 2])); 274 | } 275 | 276 | // Point to Character Generator RAM 277 | 278 | void locateCG(int i2cfile, int n) 279 | { 280 | command(i2cfile, LCD_SETCGRAMADDR + n); 281 | } 282 | 283 | 284 | void print(int i2cfile, const char *text) 285 | { 286 | int i = 0; 287 | int tlen = strlen(text); 288 | for (i = 0; i < tlen; i++) 289 | i2csend(i2cfile, text[i], LCD_RS); 290 | } 291 | 292 | // Signal Level uses a Half block defined as char 1 293 | // Use 5 chars to show 10 levels 294 | 295 | const char level[10][5] = { 296 | {1,32,32,32,32}, 297 | {255,32,32,32,32}, 298 | {255,1,32,32,32}, 299 | {255,255,32,32,32}, 300 | {255,255,1,32,32}, 301 | {255,255,255,32,32}, 302 | {255,255,255,1,32}, 303 | {255,255,255,255,32}, 304 | {255,255,255,255,1}, 305 | {255,255,255,255,255}}; 306 | 307 | 308 | void displayState() 309 | { 310 | // printtick("enter displaystate"); 311 | locate(i2cfile, 1, 0); 312 | print(i2cfile, " "); 313 | locate(i2cfile, 1, 0); 314 | print(i2cfile, ARDOPStates[ProtocolState]); 315 | // printtick("exit displaystate"); 316 | } 317 | 318 | 319 | void displayLevel(int max) 320 | { 321 | int i, j; 322 | 323 | i = max/3276; 324 | 325 | if (i > 9) 326 | i = 9; 327 | 328 | locate(i2cfile, 1, 11); 329 | 330 | for (j= 0; j < 5; j++) 331 | { 332 | i2csend(i2cfile, level[i][j], LCD_RS); 333 | } 334 | } 335 | 336 | void displayCall(int dirn, char * Call) 337 | { 338 | char paddedcall[12] = " "; 339 | 340 | paddedcall[0] = dirn; 341 | memcpy(paddedcall+1, Call, strlen(Call)); 342 | 343 | locate(i2cfile, 0, 0); 344 | print(i2cfile, paddedcall); 345 | } 346 | 347 | 348 | void initdisplay() 349 | { 350 | i2cfile = initialize("/dev/i2c-1", 0X27); 351 | 352 | Debugprintf("Returned from Init"); 353 | 354 | // Set font for half bar display for sig level 355 | 356 | locateCG(i2cfile, 0); 357 | print(i2cfile, "\x7\x7\x7\x7\x7\x7\x7\x7"); 358 | print(i2cfile, "\x1c\x1c\x1c\x1c\x1c\x1c\x1c\x1c"); 359 | } 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | -------------------------------------------------------------------------------- /ardop1ofdm/KISSModule.c: -------------------------------------------------------------------------------- 1 | // 2 | // KISS Code for ARDOPC. 3 | // 4 | // Allows Packet modes and ARDOP to coexist in same program 5 | // Mainly for Teensy Version. 6 | // 7 | // Teensy will probably only support KISS over i2c, 8 | // but for testing Windows version uses a real com port 9 | 10 | // New idea is to support via SCS Host Channel 250, but will 11 | // probably leave serial/i2c support in 12 | 13 | // Now supports KISS over SCS Channel 250 or a KISS over TCP Connection 14 | 15 | 16 | 17 | #ifdef WIN32 18 | #define _CRT_SECURE_NO_DEPRECATE 19 | #define _USE_32BIT_TIME_T 20 | 21 | #include 22 | #include 23 | #else 24 | #define HANDLE int 25 | #define SOCKET int 26 | #include 27 | #ifndef TEENSY 28 | #include 29 | #endif 30 | #endif 31 | 32 | #include "ARDOPC.h" 33 | 34 | #define FEND 0xC0 35 | #define FESC 0xDB 36 | #define TFEND 0xDC 37 | #define TFESC 0xDD 38 | 39 | 40 | HANDLE OpenCOMPort(VOID * pPort, int speed, BOOL SetDTR, BOOL SetRTS, BOOL Quiet, int Stopbits); 41 | int ReadCOMBlock(HANDLE fd, char * Block, int MaxLength); 42 | VOID ProcessKISSBlock(UCHAR * KISSBUFFER, int Len); 43 | VOID EncodePacket(UCHAR * Data, int Len); 44 | VOID ProcessKISSBytes(UCHAR * RXBUFFER, int Read); 45 | void PacketStartTX(); 46 | VOID EmCRCStuffAndSend(UCHAR * Msg, int Len); 47 | VOID ProcessKISSControlFrame(); 48 | VOID ptkSessionBG(); 49 | 50 | 51 | 52 | extern HANDLE hDevice; 53 | 54 | char KISSPORTNAME[80] = ""; // for now just support over Host Interface; 55 | 56 | HANDLE hControl; 57 | 58 | typedef struct _SERIAL_STATUS { 59 | unsigned long Errors; 60 | unsigned long HoldReasons; 61 | unsigned long AmountInInQueue; 62 | unsigned long AmountInOutQueue; 63 | BOOL EofReceived; 64 | BOOL WaitForImmediate; 65 | } SERIAL_STATUS,*PSERIAL_STATUS; 66 | 67 | // Buffers for KISS frames to and from the host. Uses cyclic buffers 68 | // Size must be modulo 2 so we can AND with mask to make cyclic 69 | 70 | #define KISSBUFFERSIZE 4096 71 | #define KISSBUFFERMASK 4095 72 | 73 | 74 | // KISS bytes from a serial, i2c or Host Mode link are placed in 75 | // the cyclic TX buffer as received. As we can only transmit complete 76 | // packets, we need some indicator of how many packets there are 77 | // in the buffer. Or maybe just how many FENDS, especially if 78 | // we remove any extra ones (just leave one at end of frame) 79 | 80 | 81 | UCHAR KISSRXBUFF[KISSBUFFERSIZE]; // Host to RF 82 | int KRXPutPtr = 0; 83 | int KRXGetPtr = 0; 84 | int FENDCount = 0; 85 | 86 | 87 | UCHAR KISSTXBUFF[KISSBUFFERSIZE]; // RF to Host 88 | int KTXPutPtr = 0; 89 | int KTXGetPtr = 0; 90 | 91 | 92 | UCHAR KISSBUFFER[500]; // Long enough for stuffed KISS frame 93 | UCHAR * RXMPTR = &KISSBUFFER[0]; 94 | int KISSLength = 0; 95 | 96 | BOOL ESCFlag = FALSE; 97 | 98 | HANDLE KISSHandle = 0; 99 | 100 | extern BOOL PacketHost; 101 | 102 | int TXDelay = 500; 103 | 104 | extern SOCKET PktSock; 105 | extern BOOL PKTCONNECTED; 106 | 107 | BOOL KISSInit() 108 | { 109 | // char * Baud = strlop(KISSPORTNAME, ','); 110 | 111 | #ifdef WIN32 112 | 113 | if (KISSPORTNAME[0]) 114 | KISSHandle = OpenCOMPort(KISSPORTNAME, 19200, FALSE, FALSE, FALSE, 0); 115 | 116 | if (KISSHandle) 117 | WriteDebugLog(LOGALERT, "KISS interface Using port %s", KISSPORTNAME); 118 | #endif 119 | 120 | return TRUE; 121 | } 122 | 123 | VOID KISSPoll() 124 | { 125 | #ifdef WIN32 126 | 127 | unsigned long Read; 128 | unsigned char RXBuffer[512]; 129 | 130 | if (KISSHandle == NULL) 131 | return; 132 | 133 | Read = ReadCOMBlock(KISSHandle, RXBuffer, 512); 134 | 135 | if (Read == 0) 136 | return; 137 | 138 | ProcessKISSBytes(RXBuffer, Read); 139 | #endif 140 | } 141 | VOID ProcessPacketBytes(UCHAR * Buffer, int Read) 142 | { 143 | // Called when frame received on TCP Packet Connection. Could be for 144 | // KISS or ARDOP Packet Session mode 145 | 146 | // Assumes that Complete KISS or Host packet will be received (pretty safe 147 | // with TCP (I hope!) 148 | 149 | // But could be more than one in buffer 150 | 151 | if (Buffer[0] == 192) 152 | ProcessKISSBytes(Buffer, Read); 153 | else 154 | { 155 | while (Read > 0) 156 | { 157 | int Used = Buffer[2] + 4; 158 | ProcessPacketHostBytes(Buffer, Read); 159 | Read -= Used; 160 | 161 | if (Read > 0) 162 | { 163 | memmove(Buffer, &Buffer[Used], Read); 164 | } 165 | } 166 | } 167 | } 168 | 169 | VOID ProcessKISSBytes(UCHAR * RXBuffer, int Read) 170 | { 171 | // Store in cyclic buffer, counting FENDS so we know if we 172 | // have a full frame in the buffer 173 | 174 | UCHAR c; 175 | 176 | WriteDebugLog(LOGALERT, "Queuing %d Packet Bytes", Read); 177 | 178 | 179 | while (Read--) 180 | { 181 | c = *(RXBuffer++); 182 | 183 | if (c == FEND) 184 | FENDCount++; 185 | 186 | KISSRXBUFF[KRXPutPtr++] = c; 187 | KRXPutPtr &= KISSBUFFERMASK; 188 | 189 | if (KRXPutPtr == KRXGetPtr) // should never happen, but nasty if it does 190 | FENDCount = 0; // Buffer is now empty 191 | } 192 | } 193 | 194 | 195 | VOID ProcessKISSByte(UCHAR c) 196 | { 197 | // Store in cyclic buffer, counting FENDS so we know if we 198 | // have a full frame in the buffer 199 | 200 | if (c == FEND) 201 | FENDCount++; 202 | 203 | KISSRXBUFF[KRXPutPtr++] = c; 204 | KRXPutPtr &= KISSBUFFERMASK; 205 | 206 | if (KRXPutPtr == KRXGetPtr) // should never happen, but nasty if it does 207 | FENDCount = 0; // Buffer is now empty 208 | } 209 | 210 | 211 | BOOL GetNextKISSFrame() 212 | { 213 | // Called to get a frame to send, either before starting or 214 | // when current frame has been sent (for back to back sends) 215 | 216 | unsigned char c; 217 | UCHAR * RXMPTR; 218 | 219 | ptkSessionBG(); // See if any session events to process 220 | 221 | if (KRXPutPtr == KRXGetPtr) // Nothing to send 222 | { 223 | ptkSessionBG(); // See if any session events to process 224 | 225 | if (KRXPutPtr == KRXGetPtr) // Still nothing to send 226 | return FALSE; // Buffer empty 227 | 228 | } 229 | if (FENDCount < 2) 230 | return FALSE; // Not a complete KISS frame 231 | 232 | if (KISSRXBUFF[KRXGetPtr++] != FEND) 233 | { 234 | // First char should always be FEND. If not Buffer has 235 | // wrapped. Remove the partial frame and discard 236 | 237 | while (KRXPutPtr != KRXGetPtr) 238 | { 239 | if (KISSRXBUFF[KRXGetPtr++] == FEND) 240 | { 241 | // Found a FEND. 242 | 243 | KRXGetPtr &= KISSBUFFERMASK; 244 | FENDCount --; 245 | 246 | // Next should also be a FEND, but can check next time round 247 | 248 | // As this shouldn't happen often, just exit and get frame next time 249 | 250 | return FALSE; 251 | } 252 | } 253 | 254 | // no FENDS in buffer!!! 255 | 256 | FENDCount = 0; // Buffer is now empty 257 | return FALSE; 258 | } 259 | 260 | // First char is a FEND, and get pointer points to next char 261 | 262 | RXMPTR = &KISSBUFFER[0]; // Initialise buffer pointer 263 | 264 | KRXGetPtr &= KISSBUFFERMASK; 265 | FENDCount --; 266 | 267 | while (KRXPutPtr != KRXGetPtr) 268 | { 269 | c = KISSRXBUFF[KRXGetPtr++]; 270 | KRXGetPtr &= KISSBUFFERMASK; 271 | 272 | if (ESCFlag) 273 | { 274 | // 275 | // FESC received - next should be TFESC or TFEND 276 | 277 | ESCFlag = FALSE; 278 | 279 | if (c == TFESC) 280 | c = FESC; 281 | 282 | if (c == TFEND) 283 | c = FEND; 284 | } 285 | else 286 | { 287 | switch (c) 288 | { 289 | case FEND: 290 | 291 | // 292 | // Either start of message or message complete 293 | // 294 | 295 | if (RXMPTR == &KISSBUFFER[0]) 296 | { 297 | // Start of Message. Shouldn't Happen 298 | FENDCount--; 299 | continue; 300 | } 301 | 302 | FENDCount--; 303 | KISSLength = RXMPTR - &KISSBUFFER[0]; 304 | 305 | // Process Control Frames here 306 | 307 | if (KISSBUFFER[0] != 0 && KISSBUFFER[0] != 6 && KISSBUFFER[0] != 12) 308 | { 309 | ProcessKISSControlFrame(); 310 | return FALSE; 311 | } 312 | 313 | return TRUE; // Got complete frame in KISSBUFFER 314 | 315 | case FESC: 316 | 317 | ESCFlag = TRUE; 318 | continue; 319 | 320 | } 321 | } 322 | 323 | // 324 | // Ok, a normal char 325 | // 326 | 327 | *(RXMPTR++) = c; 328 | 329 | if (RXMPTR == &KISSBUFFER[499]) 330 | RXMPTR--; // Protect Buffer 331 | } 332 | 333 | // We shouldnt get here, as it means FENDCOUNT is wrong. Reset it 334 | 335 | FENDCount = 0; 336 | return FALSE; 337 | } 338 | 339 | 340 | // Called by SCS Host Interface 341 | 342 | BOOL CheckKISS(UCHAR * SCSReply) 343 | { 344 | int Length = KTXPutPtr - KTXGetPtr; 345 | int n; 346 | int get = KTXGetPtr; 347 | 348 | if (Length == 0) 349 | return FALSE; 350 | 351 | if (Length < 0) 352 | Length += KISSBUFFERSIZE; 353 | 354 | // Return up to 256 chars 355 | 356 | if (Length > 256) 357 | Length = 256; 358 | 359 | n = 0; 360 | 361 | while (n < Length) 362 | { 363 | SCSReply[n++ + 5] = KISSTXBUFF[get++]; 364 | get &= KISSBUFFERMASK; 365 | } 366 | 367 | KTXGetPtr = get; 368 | 369 | SCSReply[2] = 250; 370 | SCSReply[3] = 7; 371 | SCSReply[4] = Length - 1; 372 | 373 | EmCRCStuffAndSend(SCSReply, Length + 5); 374 | return TRUE; 375 | } 376 | 377 | 378 | VOID ProcessKISSControlFrame() 379 | { 380 | } 381 | 382 | VOID SendAckModeAck() 383 | { 384 | KISSTXBUFF[KTXPutPtr++] = FEND; 385 | KTXPutPtr &= KISSBUFFERMASK; 386 | KISSTXBUFF[KTXPutPtr++] = 12; // AckMode opcode 387 | KTXPutPtr &= KISSBUFFERMASK; 388 | KISSTXBUFF[KTXPutPtr++] = KISSBUFFER[1]; 389 | KTXPutPtr &= KISSBUFFERMASK; 390 | KISSTXBUFF[KTXPutPtr++] = KISSBUFFER[2]; 391 | KTXPutPtr &= KISSBUFFERMASK; 392 | KISSTXBUFF[KTXPutPtr++] = FEND; 393 | 394 | // If using KISS over TCP, send it 395 | 396 | #ifndef TEENSY 397 | 398 | // If Using TCP, send it 399 | 400 | if (pktport) 401 | { 402 | if (PKTCONNECTED) 403 | send(PktSock, KISSTXBUFF, KTXPutPtr, 0); 404 | 405 | KTXPutPtr = 0; 406 | } 407 | 408 | #endif 409 | 410 | } 411 | 412 | void SendFrametoHost(unsigned char *data, unsigned dlen) 413 | { 414 | KISSTXBUFF[KTXPutPtr++] = FEND; 415 | KTXPutPtr &= KISSBUFFERMASK; 416 | 417 | KISSTXBUFF[KTXPutPtr++] = 0; // Data 418 | KTXPutPtr &= KISSBUFFERMASK; 419 | 420 | for (; dlen > 0; dlen--, data++) 421 | { 422 | if (*data == FEND) 423 | { 424 | KISSTXBUFF[KTXPutPtr++] = FESC; 425 | KTXPutPtr &= KISSBUFFERMASK; 426 | KISSTXBUFF[KTXPutPtr++] = TFEND; 427 | KTXPutPtr &= KISSBUFFERMASK; 428 | } 429 | else if (*data == FESC) 430 | { 431 | KISSTXBUFF[KTXPutPtr++] = FESC; 432 | KTXPutPtr &= KISSBUFFERMASK; 433 | KISSTXBUFF[KTXPutPtr++] = TFESC; 434 | KTXPutPtr &= KISSBUFFERMASK; 435 | } 436 | else 437 | { 438 | KISSTXBUFF[KTXPutPtr++] = *data; 439 | KTXPutPtr &= KISSBUFFERMASK; 440 | } 441 | } 442 | 443 | KISSTXBUFF[KTXPutPtr++] = FEND; 444 | KTXPutPtr &= KISSBUFFERMASK; 445 | 446 | #ifndef TEENSY 447 | 448 | // If Using TCP, send it 449 | 450 | if (pktport) 451 | { 452 | if (PKTCONNECTED) 453 | send(PktSock, KISSTXBUFF, KTXPutPtr, 0); 454 | 455 | KTXPutPtr = 0; 456 | } 457 | 458 | #endif 459 | } 460 | 461 | 462 | 463 | -------------------------------------------------------------------------------- /ardop2ofdm/KISSModule.c: -------------------------------------------------------------------------------- 1 | // 2 | // KISS Code for ARDOPC. 3 | // 4 | // Allows Packet modes and ARDOP to coexist in same program 5 | // Mainly for Teensy Version. 6 | // 7 | // Teensy will probably only support KISS over i2c, 8 | // but for testing Windows version uses a real com port 9 | 10 | // New idea is to support via SCS Host Channel 250, but will 11 | // probably leave serial/i2c support in 12 | 13 | // Now supports KISS over SCS Channel 250 or a KISS over TCP Connection 14 | 15 | 16 | 17 | #ifdef WIN32 18 | #define _CRT_SECURE_NO_DEPRECATE 19 | #define _USE_32BIT_TIME_T 20 | 21 | #include 22 | #include 23 | #else 24 | #define HANDLE int 25 | #define SOCKET int 26 | #include 27 | #ifndef TEENSY 28 | #include 29 | #endif 30 | #endif 31 | 32 | #include "ARDOPC.h" 33 | 34 | #define FEND 0xC0 35 | #define FESC 0xDB 36 | #define TFEND 0xDC 37 | #define TFESC 0xDD 38 | 39 | 40 | HANDLE OpenCOMPort(VOID * pPort, int speed, BOOL SetDTR, BOOL SetRTS, BOOL Quiet, int Stopbits); 41 | int ReadCOMBlock(HANDLE fd, char * Block, int MaxLength); 42 | VOID ProcessKISSBlock(UCHAR * KISSBUFFER, int Len); 43 | VOID EncodePacket(UCHAR * Data, int Len); 44 | VOID ProcessKISSBytes(UCHAR * RXBUFFER, int Read); 45 | void PacketStartTX(); 46 | VOID EmCRCStuffAndSend(UCHAR * Msg, int Len); 47 | VOID ProcessKISSControlFrame(); 48 | VOID ptkSessionBG(); 49 | 50 | 51 | 52 | extern HANDLE hDevice; 53 | 54 | char KISSPORTNAME[80] = ""; // for now just support over Host Interface; 55 | 56 | HANDLE hControl; 57 | 58 | typedef struct _SERIAL_STATUS { 59 | unsigned long Errors; 60 | unsigned long HoldReasons; 61 | unsigned long AmountInInQueue; 62 | unsigned long AmountInOutQueue; 63 | BOOL EofReceived; 64 | BOOL WaitForImmediate; 65 | } SERIAL_STATUS,*PSERIAL_STATUS; 66 | 67 | // Buffers for KISS frames to and from the host. Uses cyclic buffers 68 | // Size must be modulo 2 so we can AND with mask to make cyclic 69 | 70 | #define KISSBUFFERSIZE 4096 71 | #define KISSBUFFERMASK 4095 72 | 73 | 74 | // KISS bytes from a serial, i2c or Host Mode link are placed in 75 | // the cyclic TX buffer as received. As we can only transmit complete 76 | // packets, we need some indicator of how many packets there are 77 | // in the buffer. Or maybe just how many FENDS, especially if 78 | // we remove any extra ones (just leave one at end of frame) 79 | 80 | 81 | UCHAR KISSRXBUFF[KISSBUFFERSIZE]; // Host to RF 82 | int KRXPutPtr = 0; 83 | int KRXGetPtr = 0; 84 | int FENDCount = 0; 85 | 86 | 87 | UCHAR KISSTXBUFF[KISSBUFFERSIZE]; // RF to Host 88 | int KTXPutPtr = 0; 89 | int KTXGetPtr = 0; 90 | 91 | 92 | UCHAR KISSBUFFER[500]; // Long enough for stuffed KISS frame 93 | UCHAR * RXMPTR = &KISSBUFFER[0]; 94 | int KISSLength = 0; 95 | 96 | BOOL ESCFlag = FALSE; 97 | 98 | HANDLE KISSHandle = 0; 99 | 100 | extern BOOL PacketHost; 101 | 102 | int TXDelay = 500; 103 | 104 | extern SOCKET PktSock; 105 | extern BOOL PKTCONNECTED; 106 | 107 | BOOL KISSInit() 108 | { 109 | // char * Baud = strlop(KISSPORTNAME, ','); 110 | 111 | #ifdef WIN32 112 | 113 | if (KISSPORTNAME[0]) 114 | KISSHandle = OpenCOMPort(KISSPORTNAME, 19200, FALSE, FALSE, FALSE, 0); 115 | 116 | if (KISSHandle) 117 | WriteDebugLog(LOGALERT, "KISS interface Using port %s", KISSPORTNAME); 118 | #endif 119 | 120 | return TRUE; 121 | } 122 | 123 | VOID KISSPoll() 124 | { 125 | #ifdef WIN32 126 | 127 | unsigned long Read; 128 | unsigned char RXBuffer[512]; 129 | 130 | if (KISSHandle == NULL) 131 | return; 132 | 133 | Read = ReadCOMBlock(KISSHandle, RXBuffer, 512); 134 | 135 | if (Read == 0) 136 | return; 137 | 138 | ProcessKISSBytes(RXBuffer, Read); 139 | #endif 140 | } 141 | VOID ProcessPacketBytes(UCHAR * Buffer, int Read) 142 | { 143 | // Called when frame received on TCP Packet Connection. Could be for 144 | // KISS or ARDOP Packet Session mode 145 | 146 | // Assumes that Complete KISS or Host packet will be received (pretty safe 147 | // with TCP (I hope!) 148 | 149 | // But could be more than one in buffer 150 | 151 | if (Buffer[0] == 192) 152 | ProcessKISSBytes(Buffer, Read); 153 | else 154 | { 155 | while (Read > 0) 156 | { 157 | int Used = Buffer[2] + 4; 158 | ProcessPacketHostBytes(Buffer, Read); 159 | Read -= Used; 160 | 161 | if (Read > 0) 162 | { 163 | memmove(Buffer, &Buffer[Used], Read); 164 | } 165 | } 166 | } 167 | } 168 | 169 | VOID ProcessKISSBytes(UCHAR * RXBuffer, int Read) 170 | { 171 | // Store in cyclic buffer, counting FENDS so we know if we 172 | // have a full frame in the buffer 173 | 174 | UCHAR c; 175 | 176 | WriteDebugLog(LOGALERT, "Queuing %d Packet Bytes", Read); 177 | 178 | 179 | while (Read--) 180 | { 181 | c = *(RXBuffer++); 182 | 183 | if (c == FEND) 184 | FENDCount++; 185 | 186 | KISSRXBUFF[KRXPutPtr++] = c; 187 | KRXPutPtr &= KISSBUFFERMASK; 188 | 189 | if (KRXPutPtr == KRXGetPtr) // should never happen, but nasty if it does 190 | FENDCount = 0; // Buffer is now empty 191 | } 192 | } 193 | 194 | 195 | VOID ProcessKISSByte(UCHAR c) 196 | { 197 | // Store in cyclic buffer, counting FENDS so we know if we 198 | // have a full frame in the buffer 199 | 200 | if (c == FEND) 201 | FENDCount++; 202 | 203 | KISSRXBUFF[KRXPutPtr++] = c; 204 | KRXPutPtr &= KISSBUFFERMASK; 205 | 206 | if (KRXPutPtr == KRXGetPtr) // should never happen, but nasty if it does 207 | FENDCount = 0; // Buffer is now empty 208 | } 209 | 210 | 211 | BOOL GetNextKISSFrame() 212 | { 213 | // Called to get a frame to send, either before starting or 214 | // when current frame has been sent (for back to back sends) 215 | 216 | unsigned char c; 217 | UCHAR * RXMPTR; 218 | 219 | ptkSessionBG(); // See if any session events to process 220 | 221 | if (KRXPutPtr == KRXGetPtr) // Nothing to send 222 | { 223 | ptkSessionBG(); // See if any session events to process 224 | 225 | if (KRXPutPtr == KRXGetPtr) // Still nothing to send 226 | return FALSE; // Buffer empty 227 | 228 | } 229 | if (FENDCount < 2) 230 | return FALSE; // Not a complete KISS frame 231 | 232 | if (KISSRXBUFF[KRXGetPtr++] != FEND) 233 | { 234 | // First char should always be FEND. If not Buffer has 235 | // wrapped. Remove the partial frame and discard 236 | 237 | while (KRXPutPtr != KRXGetPtr) 238 | { 239 | if (KISSRXBUFF[KRXGetPtr++] == FEND) 240 | { 241 | // Found a FEND. 242 | 243 | KRXGetPtr &= KISSBUFFERMASK; 244 | FENDCount --; 245 | 246 | // Next should also be a FEND, but can check next time round 247 | 248 | // As this shouldn't happen often, just exit and get frame next time 249 | 250 | return FALSE; 251 | } 252 | } 253 | 254 | // no FENDS in buffer!!! 255 | 256 | FENDCount = 0; // Buffer is now empty 257 | return FALSE; 258 | } 259 | 260 | // First char is a FEND, and get pointer points to next char 261 | 262 | RXMPTR = &KISSBUFFER[0]; // Initialise buffer pointer 263 | 264 | KRXGetPtr &= KISSBUFFERMASK; 265 | FENDCount --; 266 | 267 | while (KRXPutPtr != KRXGetPtr) 268 | { 269 | c = KISSRXBUFF[KRXGetPtr++]; 270 | KRXGetPtr &= KISSBUFFERMASK; 271 | 272 | if (ESCFlag) 273 | { 274 | // 275 | // FESC received - next should be TFESC or TFEND 276 | 277 | ESCFlag = FALSE; 278 | 279 | if (c == TFESC) 280 | c = FESC; 281 | 282 | if (c == TFEND) 283 | c = FEND; 284 | } 285 | else 286 | { 287 | switch (c) 288 | { 289 | case FEND: 290 | 291 | // 292 | // Either start of message or message complete 293 | // 294 | 295 | if (RXMPTR == &KISSBUFFER[0]) 296 | { 297 | // Start of Message. Shouldn't Happen 298 | FENDCount--; 299 | continue; 300 | } 301 | 302 | FENDCount--; 303 | KISSLength = RXMPTR - &KISSBUFFER[0]; 304 | 305 | // Process Control Frames here 306 | 307 | if (KISSBUFFER[0] != 0 && KISSBUFFER[0] != 6 && KISSBUFFER[0] != 12) 308 | { 309 | ProcessKISSControlFrame(); 310 | return FALSE; 311 | } 312 | 313 | return TRUE; // Got complete frame in KISSBUFFER 314 | 315 | case FESC: 316 | 317 | ESCFlag = TRUE; 318 | continue; 319 | 320 | } 321 | } 322 | 323 | // 324 | // Ok, a normal char 325 | // 326 | 327 | *(RXMPTR++) = c; 328 | 329 | if (RXMPTR == &KISSBUFFER[499]) 330 | RXMPTR--; // Protect Buffer 331 | } 332 | 333 | // We shouldnt get here, as it means FENDCOUNT is wrong. Reset it 334 | 335 | FENDCount = 0; 336 | return FALSE; 337 | } 338 | 339 | 340 | // Called by SCS Host Interface 341 | 342 | BOOL CheckKISS(UCHAR * SCSReply) 343 | { 344 | int Length = KTXPutPtr - KTXGetPtr; 345 | int n; 346 | int get = KTXGetPtr; 347 | 348 | if (Length == 0) 349 | return FALSE; 350 | 351 | if (Length < 0) 352 | Length += KISSBUFFERSIZE; 353 | 354 | // Return up to 256 chars 355 | 356 | if (Length > 256) 357 | Length = 256; 358 | 359 | n = 0; 360 | 361 | while (n < Length) 362 | { 363 | SCSReply[n++ + 5] = KISSTXBUFF[get++]; 364 | get &= KISSBUFFERMASK; 365 | } 366 | 367 | KTXGetPtr = get; 368 | 369 | SCSReply[2] = 250; 370 | SCSReply[3] = 7; 371 | SCSReply[4] = Length - 1; 372 | 373 | EmCRCStuffAndSend(SCSReply, Length + 5); 374 | return TRUE; 375 | } 376 | 377 | 378 | VOID ProcessKISSControlFrame() 379 | { 380 | } 381 | 382 | VOID SendAckModeAck() 383 | { 384 | KISSTXBUFF[KTXPutPtr++] = FEND; 385 | KTXPutPtr &= KISSBUFFERMASK; 386 | KISSTXBUFF[KTXPutPtr++] = 12; // AckMode opcode 387 | KTXPutPtr &= KISSBUFFERMASK; 388 | KISSTXBUFF[KTXPutPtr++] = KISSBUFFER[1]; 389 | KTXPutPtr &= KISSBUFFERMASK; 390 | KISSTXBUFF[KTXPutPtr++] = KISSBUFFER[2]; 391 | KTXPutPtr &= KISSBUFFERMASK; 392 | KISSTXBUFF[KTXPutPtr++] = FEND; 393 | 394 | // If using KISS over TCP, send it 395 | 396 | #ifndef TEENSY 397 | 398 | // If Using TCP, send it 399 | 400 | if (pktport) 401 | { 402 | if (PKTCONNECTED) 403 | send(PktSock, KISSTXBUFF, KTXPutPtr, 0); 404 | 405 | KTXPutPtr = 0; 406 | } 407 | 408 | #endif 409 | 410 | } 411 | 412 | void SendFrametoHost(unsigned char *data, unsigned dlen) 413 | { 414 | KISSTXBUFF[KTXPutPtr++] = FEND; 415 | KTXPutPtr &= KISSBUFFERMASK; 416 | 417 | KISSTXBUFF[KTXPutPtr++] = 0; // Data 418 | KTXPutPtr &= KISSBUFFERMASK; 419 | 420 | for (; dlen > 0; dlen--, data++) 421 | { 422 | if (*data == FEND) 423 | { 424 | KISSTXBUFF[KTXPutPtr++] = FESC; 425 | KTXPutPtr &= KISSBUFFERMASK; 426 | KISSTXBUFF[KTXPutPtr++] = TFEND; 427 | KTXPutPtr &= KISSBUFFERMASK; 428 | } 429 | else if (*data == FESC) 430 | { 431 | KISSTXBUFF[KTXPutPtr++] = FESC; 432 | KTXPutPtr &= KISSBUFFERMASK; 433 | KISSTXBUFF[KTXPutPtr++] = TFESC; 434 | KTXPutPtr &= KISSBUFFERMASK; 435 | } 436 | else 437 | { 438 | KISSTXBUFF[KTXPutPtr++] = *data; 439 | KTXPutPtr &= KISSBUFFERMASK; 440 | } 441 | } 442 | 443 | KISSTXBUFF[KTXPutPtr++] = FEND; 444 | KTXPutPtr &= KISSBUFFERMASK; 445 | 446 | #ifndef TEENSY 447 | 448 | // If Using TCP, send it 449 | 450 | if (pktport) 451 | { 452 | if (PKTCONNECTED) 453 | send(PktSock, KISSTXBUFF, KTXPutPtr, 0); 454 | 455 | KTXPutPtr = 0; 456 | } 457 | 458 | #endif 459 | } 460 | 461 | 462 | 463 | --------------------------------------------------------------------------------