maanantai, 19. huhtikuu 2021

Modifying old SDR# TETRA demod plug-in 2

https://teknokoodiradio.vuodatus.net/lue/2021/03/modifying-old-sdr-tetra-demod-plug-in
 

Visual Studio 2019 Community Edition
C#, .NET 4.6
dotPeek
SDRSharp.Tetra.dll - TETRA demodulator plug-in version 1.0.10.1

Reverse engineering SDRSharp.Tetra.dll with dotPeek

Modifying old SDR# TETRA demod plug-in to display PDU element info.

    public void UpdateTextBox(List<Dictionary<GlobalNames, int>> rawData)
    {
      string str1 = string.Empty;
      StringBuilder sb = new StringBuilder();
      int num1 = 0;

            //ADDX
            pdu_timestamp = ""; // DateTime.Now.ToString("yyyyMMddHHmmss") + " ";
            //ADDX

      while (rawData.Count > 0)
      {
        Dictionary<GlobalNames, int> dictionary = rawData[0];
        try
        {
          int count = dictionary.Count;
        }
        catch
        {
          return;
        }

                // ADDX
                //if (GlobalFunction._pduTxt.Trim().Length > 0)
                //{
                //    this.callsTextBox.AppendText(GlobalFunction._pduTxt + Environment.NewLine);
                //    pduLog.WriteLine(GlobalFunction._pduTxt);
                //    GlobalFunction._pduTxt = "";
                //}
                sb.Clear();
                int namesCount = Enum.GetNames(typeof(GlobalNames)).Length;
                for (int gnc = 0; gnc < namesCount; gnc++)
                {
                    if (dictionary.TryGetValue((GlobalNames)gnc, out num1))
                    {
                        sb.Append(Enum.GetName(typeof(GlobalNames), gnc) + ": " + num1.ToString() + ";");
                    }
                }
                if (namesCount != 0)
                {
                    pduLog.WriteLine(sb.ToString());
                }

                // ADDX
                

                if (dictionary.TryGetValue(GlobalNames.Unallocated_slot1, out num1))
...

tetra-mac-data.jpg

https://i.ibb.co/HYypmHT/tetra-mac-data.jpg

maanantai, 12. huhtikuu 2021

Super simple LoraWAN rx for Arduino/SX127x

#include <SPI.h>

#define SERIAL_SPEED        9600

#define LORA_FREQ           869.525
#define STATE_SLEEP         0
#define STATE_STANDBY       1
#define STATE_FSRX          4
#define STATE_RX            5
#define S_DELAY             10
#define L_DELAY             100
#define RX_BUFFER_LEN       255
#define SX_FREQ             "Frequency "
#define SX_VERSION          "Chip version "
#define PRINT_MODEM_STAT
#undef PRINT_MODEM_STAT

#define RegFifo               0x00
#define RegOpMode             0x01
#define RegFrMsb              0x06
#define RegFrMid              0x07
#define RegFrLsb              0x08
#define RegFifoRxCurrentAddr  0x10
#define RegFifoAddrPtr        0x0D
#define RegIrqFlagsMask       0x11
#define RegIrqFlags           0x12
#define RegRxNbBytes          0x13
#define RegModemStat          0x18
#define RegPktSnrValue        0x19
#define RegPktRssiValue       0x1A
#define RegRssiValue          0x1B
#define RegHopChannel         0x1C
#define RegModemConfig1       0x1D
#define RegModemConfig2       0x1E
#define RegVersion            0x42

#define SX_OSC_FREQ         32000000
#define SX_RESET            9
#define SX_RESET_DELAY_H    5
#define SX_RESET_DELAY_L    100
#define SPI_SS              10
#define SPI_RW_DELAY        50

uint8_t modemStat;
uint8_t rxBuffer[RX_BUFFER_LEN];

void setup() {
  Serial.begin(SERIAL_SPEED);
  if (initSX()) {
    memset(rxBuffer, 0, RX_BUFFER_LEN);
    uint8_t r = readSPI(RegVersion);
    Serial.print(F(SX_VERSION));
    char strVer[4];
    snprintf(strVer, 4, "%1u.%1u", r >> 4 , r & 0x0F);
    Serial.println(strVer);
    Serial.println();
    startLora();

    setFreq(LORA_FREQ);
    Serial.print(F(SX_FREQ));
    Serial.println(LORA_FREQ, DEC);

// Set SF12, CR 4/5, explicit header mode
    r = readSPI(RegModemConfig2);
    r = r & B11000000;
    writeSPI(RegModemConfig2, r);
// Set BW 125 kHz
    r = readSPI(RegModemConfig1);
    bitSet(r, 6); bitSet(r, 5); bitSet(r, 4);
    writeSPI(RegModemConfig1, r);
    
    setState(STATE_FSRX);
    delay(L_DELAY);
    setState(STATE_RX);
    delay(S_DELAY);

#ifdef PRINT_MODEM_STAT
    modemStat = readSPI(RegModemStat);
    Serial.println();
    Serial.print(F("Modem status: "));
    Serial.print("\t");
    Serial.print(modemStat, BIN);
    Serial.println();
#endif
  }
}

void loop() {
  uint8_t r;
#ifdef PRINT_MODEM_STAT
  r = readSPI(RegModemStat);
  if (r != modemStat) {
    modemStat = r;
    Serial.println();
    Serial.print(F("Modem status: "));
    Serial.print("\t");
    Serial.print(r, BIN);
    Serial.println();
  }
#endif
  if (getRxState() == 1) {
    r = readFifo(rxBuffer, RX_BUFFER_LEN);
    if (r > 0) {
      Serial.println();
      for (uint8_t i = 0; i < r; i++) {
        Serial.print(rxBuffer[i], HEX);
      }
      Serial.println();
    }
    clearLoraIrqFlags();
    memset(rxBuffer, 0, RX_BUFFER_LEN);
  }
}

void setFreq(float f)
{
  uint32_t lf = (f * 1000000) / 61.035;
  writeSPI(RegFrMsb, (lf >> 16) & 0xff);
  writeSPI(RegFrMid, (lf >> 8) & 0xff);
  writeSPI(RegFrLsb, lf & 0xff);
}

void setState(uint8_t s) {
  uint8_t b = readSPI(RegOpMode);
  bitClear(b, 2);
  bitClear(b, 1);
  bitClear(b, 0);
  switch (s) {
    case STATE_SLEEP:
    {
      break;
    }
    case STATE_STANDBY:
    {
      bitSet(b, 0);
      break;
    }
    case STATE_FSRX:
    {
      bitSet(b, 2);
      break;
    }
    case STATE_RX:
    {
      bitSet(b, 2);
      bitSet(b, 0);
      break;
    }
  }
  writeSPI(RegOpMode, b);
}

void startLora()
{
  setState(STATE_SLEEP);
  uint8_t b = readSPI(RegOpMode);
  bitSet(b, 7);
  writeSPI(RegOpMode, b);
}

uint8_t getLoraIrqFlag(uint8_t v) {
  return bitRead(readSPI(RegIrqFlags), v);
}

void clearLoraIrqFlag(uint8_t v) {
  uint8_t b = readSPI(RegIrqFlags);
  bitSet(b, v);
  writeSPI(RegIrqFlags, b);
}

void clearLoraIrqFlags() {
  writeSPI(RegIrqFlags, 0xFF);
}

int16_t pktRssiValue() {
  return (int16_t) (-164 + readSPI(RegPktRssiValue));
}

int16_t rssiValue() {
  return (int16_t) (-164 + readSPI(RegRssiValue));
}

uint8_t lastPktSnrValue()
{
  return (readSPI(RegPktSnrValue) >> 2);
}

int8_t getRxState() {
  uint8_t b = readSPI(RegIrqFlags);
  if (bitRead(b, 6)) {
    return 1; // packet rx
  }
  if (bitRead(b, 7)) {
    return -1; // timeout
  }
  return 0;
}

void discardFifo()
{
  uint8_t b = readSPI(RegFifoRxCurrentAddr);
  writeSPI(RegFifoAddrPtr, b);  
  uint8_t n = readSPI(RegRxNbBytes);
  writeSPI(RegFifoAddrPtr, 0);
  for (b = 0; b < n; b++) {
    readSPI(RegFifo);
  }
}

uint8_t readFifo(uint8_t buf[], uint8_t buf_len)
{
  uint8_t l = 0;
  writeSPI(RegFifoAddrPtr, readSPI(RegFifoRxCurrentAddr));
  uint8_t n = readSPI(RegRxNbBytes);
  if (buf_len < n) {
    l = buf_len;
  }
  else {
    l = n;
  }
  uint8_t i;
  for(i = 0; i < l; i++) {
    buf[i] = readSPI(RegFifo);
  }
  uint8_t cnt = n - buf_len;
  if (cnt > 0) {
    for (i = 0; i < cnt; i++) {
      readSPI(RegFifo);
    }
  }
  return l;
}

// Parse LoRa class B device beacon (RX2) downlink message
// https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5038744/
void parseLoraMsg(uint8_t rxPacket[]) {
    uint16_t i;
    Serial.println(F("PHYPayload MHDR:"));
    Serial.print(F("MType: "));
    Serial.print((rxPacket[0] & B11100000) >> 5);
    Serial.print("\t");
    Serial.print(F("RFU: "));
    Serial.print((rxPacket[0] & B00011100) >> 2);
    Serial.print("\t");
    Serial.print(F("Major: "));
    Serial.println(rxPacket[0] & B00000011);
    Serial.println(F("MACPayload FHDR: "));
    Serial.print(F("DevAddr: "));
    for (i = 1; i < 5; i++) {
      Serial.print(rxPacket[i]);
    }
    Serial.println("");
    Serial.print((rxPacket[1] & B11111110) >> 1);
    Serial.println("");
    Serial.print(F("FCtrl:\tADR: "));
    Serial.print((rxPacket[5] & B10000000) >> 7);
    Serial.print(F(" ADRAckReq: "));
    Serial.print((rxPacket[5] & B01000000) >> 6);
    Serial.print(F(" ACK: "));
    Serial.print((rxPacket[5] & B00100000) >> 5);
    Serial.print(F(" RFU: "));
    Serial.print((rxPacket[5] & B00010000) >> 4);
    Serial.print(F(" FOptsLen: "));
    uint8_t foptslen = rxPacket[5] & B00001111;
    Serial.println(foptslen);
    Serial.print(F("FCnt: "));
    Serial.print(rxPacket[6]);
    Serial.print(rxPacket[7]);
    if (foptslen > 0) {
      Serial.println("");
      Serial.print(F("FOpts: (MACCommand(s) byte 1: CID, bytes 2-4: Args) "));
      for (i = 8; i < (8 + foptslen); i++) {
        Serial.print(rxPacket[i]);
      }
      foptslen = i;
    }
    else {
      foptslen = 8;
    }
    Serial.println("");
    Serial.print(F("FPort: "));
    Serial.print(rxPacket[foptslen]);
}

bool initSX() {
  pinMode(SX_RESET, OUTPUT);
  resetSX();
  initSPI();
  if (readSPI(RegVersion) == 0) {
    return false;
  }
  setState(STATE_STANDBY);
  return true;
}

void resetSX() {
  digitalWrite(SX_RESET, LOW);
  delayMicroseconds(SX_RESET_DELAY_L);
  digitalWrite(SX_RESET, HIGH);
  delay(SX_RESET_DELAY_H);
}

uint8_t readSPI(uint8_t addr) {
  digitalWrite(SPI_SS, LOW);
  SPI.transfer(addr);
  delayMicroseconds(SPI_RW_DELAY);
  uint8_t v = SPI.transfer(0x00);
  digitalWrite(SPI_SS, HIGH);
  return v;
}

void writeSPI(uint8_t addr, uint8_t v) {
  digitalWrite(SPI_SS, LOW);
  SPI.transfer(addr | 0x80);
  delayMicroseconds(SPI_RW_DELAY);
  SPI.transfer(v);
  digitalWrite(SPI_SS, HIGH);
}

void initSPI()
{
  digitalWrite(SPI_SS, HIGH);
  pinMode(SPI_SS, OUTPUT);
  SPI.begin();
  SPI.setDataMode(SPI_MODE0);
  SPI.setBitOrder(MSBFIRST);
}

simplerx.jpg

 

torstai, 8. huhtikuu 2021

Installing gr-dect2 on Oracle VM VirtualBox/Ubuntu 20.04

sudo apt-get update
sudo apt install rtl-sdr
sudo add-apt-repository ppa:gnuradio/gnuradio-releases-3.8
sudo apt install gnuradio
sudo apt install gr-osmosdr
sudo apt install cmake
sudo apt install build-essential
sudo apt install swig
sudo apt install doxygen
sudo apt install git
sudo apt-get install libgmp3-dev
sudo apt-get install libsndfile1-dev
git clone git://github.com/pavelyazev/gr-dect2.git
cd gr-dect2
mkdir build
cd build
cmake ..
make
sudo make install
sudo ldconfig

Gnuradio companion should be used to open and run the flow graph dect2.grc from gr-dect/grc

tiistai, 30. maaliskuu 2021

Installing gr-gsm and re-DECTed on Oracle VM VirtualBox/Ubuntu 18.04

Oracle VM VirtualBox
Ubuntu 18.04 LTS

sudo add-apt-repository ppa:gnuradio/gnuradio-releases-3.7
sudo apt-get update
sudo apt install gnuradio

sudo apt install -y
rtl-sdr
librtlsdr-dev
osmo-sdr
libosmosdr-dev
libosmocore
libosmocore-dev
cmake
libboost-all-dev
libcppunit-dev
swig doxygen liblog4cpp5-dev
python-scipy git build-essential
autoconf libtool pkg-config libc6-dev
gr-osmosdr
libcanberra-gtk-module


(export PYTHONPATH=/usr/local/lib/python3/dist-packages/:$PYTHONPATH *)

cd $HOME
mkdir rf
cd rf
 
git clone https://github.com/velichkov/gr-gsm.git
cd gr-gsm
mkdir build
cd build
cmake ..
mkdir $HOME/.grc_gnuradio/ $HOME/.gnuradio/
make
sudo make install
sudo ldconfig

(sudo cp -r /usr/local/lib/python3/dist-packages/grgsm/ /usr/lib/python3/dist-packages/ *)

* not needed to do, try if you encounter problems

gr-gsm-vm.jpg

https://i.ibb.co/HPnjTbC/gr-gsm-vm.jpg

2G still quite active
imsicatch.jpg

https://i.ibb.co/XpPngMh/imsicatch.jpg


re-DECTed

git clone https://github.com/znuh/re-DECTed.git
sudo apt install net-tools
cd re-DECTed
cd SDR
make
sudo ip link add dummy0 type dummy
sudo ifconfig dummy0 up
sudo ./dectrcv

open second terminal
~/re-DECTed/SDR$ ./dectrx_37.py

perjantai, 26. maaliskuu 2021

SDR# TETRA demod plug-in UDP output

SDR# TETRA demod plug-in: http://rtl-sdr.ru/page/plagin-dlja-priema-tetra (https://github.com/vgpastor/SDR-Tetra-Plugin) features UDP output port in config.
Tetra-rx program (MSYS2 required in Windows) accepts its output data (which is demodulated dibits)

tetra-rx.jpg

Wireshark adapter for capturing local loopback traffic shows tetra-rx messages

ws-tetra.jpg

Raw data logging in Wireshark can be done with local loopback traffic capture by using capture filter udp port x

 

  • Kuvia