Single Channel Packet Forwarder part 2 [Deprecated]


Single channel packet forwarders are NOT supported by The Things Network and we condemn their use.

Single Channel Packet Forwarders are not LoRaWAN compliant gateways.

They negatively impact proper operation of gateways and end devices (nodes) in their area which means they negatively impact The Things Network and its users, but they also impact other LoRaWAN operators. Not only now, but also in the future when new nodes and new gateways are added in the area.

Single Channel Packet Forwarders are often called Single Channel Gateways which is incorrect, confusing and misleading. They shall not be called gateways.

Be aware that some vendors will try to sell Single Channel Packet Forwarders as a gateway which they are not. These cannot be used as gateway for The Things Network.

NOT supported also means that single channel packet forwarders may no longer work after the community network will be migrated to V3.

Only LoRaWAN compliant gateways are supported by The Things Network.


Years ago in the early days of The Things Network, LoRaWAN gateways were very expensive and out of reach for many. In those days a Single Channel Packet Forwarder was an affordable alternative to start experimenting with the technology and The Things Network.

During recent years much cheaper and much more affordable gateways have become available. The Things Indoor Gateway costs around €85 (VAT included) and there are many options for both DIY and commercial gateways in the price range from €120 to €200.

In the last years many gateways have been deployed worldwide and network coverage has become available in many areas on the globe. The effect and importance of the negative impact of Single Channel Packet Forwarders on successful operation of the network and its users has substantially increased with the growth of the network. Therefore use of Single Channel Packet Forwarders is now deprecated and is condemned by The Things Network and on this forum.

(end of disclaimer)

Single Channel Gateway part 1

I’m doing tests using Lora-GPS-Hat RPI and a GPS-Lora Dragino node.

For the GW I am using the code of “single_chan_pkt_fwd” and in arduino this code

 * Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman
 * Permission is hereby granted, free of charge, to anyone
 * obtaining a copy of this document and accompanying files,
 * to do whatever they want with them without any restriction,
 * including, but not limited to, copying, modification and redistribution.
 * This example sends a valid LoRaWAN packet with payload "Hello,
 * world!", using frequency and encryption settings matching those of
 * the (early prototype version of) The Things Network.
 * Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in g1,
 *  0.1% in g2).
 * Change DEVADDR to a unique address!
 * See
 * Do not forget to define the radio type correctly in config.h.

#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>

// LoRaWAN NwkSKey, network session key
// This is the default Semtech key, which is used by the prototype TTN
// network initially.
static const PROGMEM u1_t NWKSKEY[16] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };

// LoRaWAN AppSKey, application session key
// This is the default Semtech key, which is used by the prototype TTN
// network initially.
static const u1_t PROGMEM APPSKEY[16] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };

// LoRaWAN end-device address (DevAddr)
// See
static const u4_t DEVADDR = 0x03FF0001 ; // <-- Change this address for every node!

// These callbacks are only used in over-the-air activation, so they are
// left empty here (we cannot leave them out completely unless
// DISABLE_JOIN is set in config.h, otherwise the linker will complain).
void os_getArtEui (u1_t* buf) { }
void os_getDevEui (u1_t* buf) { }
void os_getDevKey (u1_t* buf) { }

static uint8_t mydata[] = "Hello, world!";
static osjob_t sendjob;

// Schedule TX every this many seconds (might become longer due to duty
// cycle limitations).
const unsigned TX_INTERVAL = 60;

// Pin mapping
const lmic_pinmap lmic_pins = {
    .nss = 10,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 9,
    .dio = {2, 6, 7},

void onEvent (ev_t ev) {
    Serial.print(": ");
    switch(ev) {
        case EV_SCAN_TIMEOUT:
        case EV_BEACON_FOUND:
        case EV_BEACON_MISSED:
        case EV_BEACON_TRACKED:
        case EV_JOINING:
        case EV_JOINED:
        case EV_RFU1:
        case EV_JOIN_FAILED:
        case EV_REJOIN_FAILED:
        case EV_TXCOMPLETE:
            Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
            if(LMIC.dataLen) {
                // data received in rx slot after tx
                Serial.print(F("Data Received: "));
                Serial.write(LMIC.frame+LMIC.dataBeg, LMIC.dataLen);
            // Schedule next transmission
            os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
        case EV_LOST_TSYNC:
        case EV_RESET:
        case EV_RXCOMPLETE:
            // data received in ping slot
        case EV_LINK_DEAD:
        case EV_LINK_ALIVE:
            Serial.println(F("Unknown event"));

void do_send(osjob_t* j){
    // Check if there is not a current TX/RX job running
    if (LMIC.opmode & OP_TXRXPEND) {
        Serial.println(F("OP_TXRXPEND, not sending"));
    } else {
        // Prepare upstream data transmission at the next possible time.
        LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0);
        Serial.println(F("Packet queued"));
    // Next TX is scheduled after TX_COMPLETE event.

void setup() {

    #ifdef VCC_ENABLE
    // For Pinoccio Scout boards
    pinMode(VCC_ENABLE, OUTPUT);
    digitalWrite(VCC_ENABLE, HIGH);

    // LMIC init
    // Reset the MAC state. Session and pending data transfers will be discarded.

    // Set static session parameters. Instead of dynamically establishing a session
    // by joining the network, precomputed session parameters are be provided.
    #ifdef PROGMEM
    // On AVR, these values are stored in flash and only copied to RAM
    // once. Copy them to a temporary buffer here, LMIC_setSession will
    // copy them into a buffer of its own again.
    uint8_t appskey[sizeof(APPSKEY)];
    uint8_t nwkskey[sizeof(NWKSKEY)];
    memcpy_P(appskey, APPSKEY, sizeof(APPSKEY));
    memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY));
    LMIC_setSession (0x1, DEVADDR, nwkskey, appskey);
    // If not running an AVR with PROGMEM, just use the arrays directly 
    LMIC_setSession (0x1, DEVADDR, NWKSKEY, APPSKEY);

    // Set up the channels used by the Things Network, which corresponds
    // to the defaults of most gateways. Without this, only three base
    // channels from the LoRaWAN specification are used, which certainly
    // works, so it is good for debugging, but can overload those
    // frequencies, so be sure to configure the full frequency range of
    // your network here (unless your network autoconfigures them).
    // Setting up channels should happen after LMIC_setSession, as that
    // configures the minimal channel set.
    //LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    //LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI);      // g-band
    //LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    //LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    //LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    //LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    //LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    //LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    //LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK,  DR_FSK),  BAND_MILLI);      // g2-band
    // TTN defines an additional channel at 869.525Mhz using SF9 for class B
    // devices' ping slots. LMIC does not have an easy way to define set this
    // frequency and support for class B is spotty and untested, so this
    // frequency is not configured here.

  for (int channel=0; channel<8; ++channel) {
  for (int channel=9; channel<72; ++channel) {

    // Disable link check validation

    LMIC.freq = 915000000;

    // Set data rate and transmit power (note: txpow seems to be ignored by the library)

    // Start job

void loop() {

And I only receive this data every time

3 posts were merged into an existing topic: Gateway active passing packets but not connected or claimed

Trying to set one of the RM1xx modules to act as Single Ch Gateway. Since it’s a gateway related topic thought to post it here, in case others want to use RM1xx as Single Ch Gateway for proof of concept (if possible)

Couple of issues:

  1. What pin is CS_A (NSS), DIO 0,. Trying to match the pins witch Single Channel gateway guide.

10 (CS_A) NSS 22 GPIO6
SV pin 1 DIO 0 7 GPIO7
SV pin 7 RESET 11 GPIO0

Found here:

Do I define CS_A (NSS), DIO 0 in RM1xx module software with any available SIO_ pin? I’m on Mini board.

  1. I’ve compiled the single_chan_pkt_fwd as described in this post. I guess this code will run on RPi or another microcontroller. What gets loaded to RM1xx LoRAWAN module to receive data from another RM1xx module and pass it to Raspberry pi.

that’s not possible with the code you mentioned.

It’s not possible to use RM1xx to act as a single ch gateway with RPi? I thought single_ch_pkt_fwd runs on RPi and just grabs data off of LoRA module.

Is it the matter of editing the code from here to match RM1xx pins?

I thought these modules follow a standard for LoRa communication.

the RM1xx lora modules are not compatible with the rfm95 modules used in the single channel gateways, apples and pears.

I thought all these modules are just a breakout for SX chips and saw the library indicate it works with SX1272. Can one RFM95W, such as this:

Acting as a single channel gateway receive data packets from RM1xx module?

Found this in a different thread, doesn’t get much into details if it actually worked: Anyone tried Laird RM1XX modules?

I suggest that you start catching up a bit :wink:

On a related - but more realistic - note anyone tried to use the Laird RM186 modules with single channel gateway?

Doesn’t seem to be any way of removing the 3 default LoRaWAN frequencies, while the gateway only listens on one.

Maybe I need to setup a private network and issue LoRaMAC commands to the module, or perhaps using the Channel Map in the OTAA join, but again I guess it’d have to be a private network server.

Has anyone done anything with this?

I doubt it… the rfm95/sx1272 is 3x cheaper and makes way more sense to use, plus there is a lot of code and experience out there.

Sorry I might not have made my question clear enough.

I’m asking if anyone was using the RM186 together with a Single Channel Gateway (which could be anything, a Pi, ESP8266, LoPy -not the RM186)

Essentially I’m looking for some way to lock the RM186 to a single frequency, perhaps via MAC commands or the channel map. It’s not just the RM186 that needs this, so I think this topic is the best place to ask.

1 Like

There seems to be 2 different software packages for single channel gateways with the ESP8266:


Is the first one better?

I was just got a couple of RM191 and was hoping to get Adafruit RFM95W to setup a single channel gateway. Seems like that Mini PCI-E + MTAC + Pi hack more likely.

For the RM191 you should be able to use a single channel via the ChannelsMask command.

However this is not available in the RM186, it expects the 3 mandatory LoRaWAN EU bands.

ESP-1ch-Gateway-v4.0 with RFM96 433Mhz
If I have the RFM96 433Mhz modules. can I use them with the ESP-1ch-Gateway-v4.0 ? if so what do I need to change in config file for it to work? (I saw that I need to change “freqs” array in loraModem.h but the “#define CFG_sx1276_radio” is the same…)

Alex from Pycom gave a video session today on setting up the LoPy as a single channel gateway:

I was surprised as it’s actually a small Python script which does it all, very readable, and has support for nice features like OTAA.

1 Like

@diegoalvarez Hi Diego, I am also in Australia and I am having trouble trying to get my node communicating with the gateway. Are you using the Arudino-LMIC library with the ttn sketch? What changes did you make to the sketch to get it working?

Hi all, shiva115, just FYI there are 4 people in Cairns, Australia currently trying to make single channel gateways work using a variety of different libraries, examples and codebases. From Pi to Arduino. Our common thread is we are all using the rfm95. No success so far. We have many, many questions, and lots of observations as a group, but essentially, haven’t given up. Note: We are not coding our own AU systems, just making mods to existing systems. It seems there is no combination of codebase that is robust, reliable or even works, that includes both single channel gateway and node working via TTN. If anyone has a combo that they know works, feel free to share :slight_smile:

Hey, fyi, 4:14 AM here, and I have it working!!! A single channel gateway that sends and receives! And a node that hits the right frequencies! 2x ESP8266 and 2x RFM95