NAMote72 Utility Application – Serial Terminal Monitor control for NAMote72 (note: this application replaces the previous na_mote1 test code application)

Dependencies:   SX127x lib_gps lib_mma8451q lib_mpl3115a2 lib_sx9500 mbed

Fork of na_mote1 by wayne roberts

See wiki Page for a detailed

This is a link to the wiki page

main.cpp

Committer:
dudmuck
Date:
2014-10-06
Revision:
1:b13a15a34c3f
Parent:
0:9c2b09ecb20f
Child:
2:fb41d1c4b299

File content as of revision 1:b13a15a34c3f:

#include "sx127x_lora.h"
#include "sx127x_fsk.h"

#include "mma8451q.h"
#include "mpl3115a2.h"
#include "sx9500.h"

/*
 *
 */
Serial pc(USBTX, USBRX);
DigitalInOut pb8(PB_8);
DigitalInOut pb9(PB_9);
//char _pb8, _pb9;
/*I2C i2c(I2C_SDA, I2C_SCL);
MMA8451Q mma8451q(i2c);
MPL3115A2 mpl3115a2(i2c);
SX9500 sx9500(i2c);*/

uint8_t tx_cnt;
char pcbuf[64];

typedef enum {
    APP_NONE = 0,
    APP_CHAT
} app_e;

app_e app = APP_NONE;


const uint32_t frfs[] = {   /* frequency hopping table */
    MHZ_TO_FRF(903.0),
    MHZ_TO_FRF(904.0),
    MHZ_TO_FRF(905.0),
    MHZ_TO_FRF(906.0),
    MHZ_TO_FRF(907.0),
    MHZ_TO_FRF(908.0),
    MHZ_TO_FRF(909.0),
    MHZ_TO_FRF(910.0),
    MHZ_TO_FRF(911.0),
    MHZ_TO_FRF(912.0),
    MHZ_TO_FRF(913.0),
    MHZ_TO_FRF(914.0),
    MHZ_TO_FRF(915.0)
};

#define FSK_LARGE_PKT_THRESHOLD  0x3f

/******************************************************************************/
#define RADIO_RESET              PC_2 //NorAm_Mote Reset_sx
#define RADIO_MOSI               PB_15 //NorAm_Mote SPI2 Mosi
#define RADIO_MISO               PB_14 //NorAm_Mote SPI2 Miso
#define RADIO_SCLK               PB_13 //NorAm_Mote  SPI2 Clk
#define RADIO_NSS                PB_12 //NorAm_Mote SPI2 Nss

#define RADIO_DIO_0              PC_6 //NorAm_Mote DIO0 
#define RADIO_DIO_1              PC_10 //NorAm_Mote DIO1 
#define RADIO_DIO_2              PC_8 //NorAm_Mote DIO2 
#define RADIO_DIO_3              PB_4 //NorAm_Mote DIO3 
#define RADIO_DIO_4              PB_5 //NorAm_Mote DIO4 
#define RADIO_DIO_5              PB_6 //NorAm_Mote DIO5

#define RFSW1                    PC_4 //NorAm_Mote RFSwitch_CNTR_1
#define RFSW2                    PC_13 //NorAm_Mote RFSwitch_CNTR_2

//  pin:       3     8     1      7    10    12     5   20    18
//                 mosi,       miso,       sclk,        cs,         rst,        dio0,        dio1, fctx, fcps 
//SX127x radio(D11,   D12, D13,    D10,  D7,   D2,   D3,  D8,  D9); // nucleo-L152RE
SX127x radio(RADIO_MOSI, RADIO_MISO, RADIO_SCLK, RADIO_NSS, RADIO_RESET, RADIO_DIO_0, RADIO_DIO_1, RFSW1, RFSW2); // NA-mote
SX127x_fsk fsk(radio);
SX127x_lora lora(radio);

void printLoraIrqs_(bool clear)
{
    //in radio class -- RegIrqFlags_t RegIrqFlags;

    //already read RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS);
    printf("\r\nIrqFlags:");
    if (lora.RegIrqFlags.bits.CadDetected)
        printf("CadDetected ");
    if (lora.RegIrqFlags.bits.FhssChangeChannel) {
        //radio.RegHopChannel.octet = radio.read_reg(REG_LR_HOPCHANNEL);
        printf("FhssChangeChannel:%d ", lora.RegHopChannel.bits.FhssPresentChannel);
    }
    if (lora.RegIrqFlags.bits.CadDone)
        printf("CadDone ");
    if (lora.RegIrqFlags.bits.TxDone)
        printf("TxDone ");
    if (lora.RegIrqFlags.bits.ValidHeader)
        printf("ValidHeader ");
    if (lora.RegIrqFlags.bits.PayloadCrcError)
        printf("PayloadCrcError ");
    if (lora.RegIrqFlags.bits.RxDone)
        printf("RxDone ");  
    if (lora.RegIrqFlags.bits.RxTimeout)
        printf("RxTimeout ");

    printf("\r\n");

    if (clear)
        radio.write_reg(REG_LR_IRQFLAGS, lora.RegIrqFlags.octet);

}

void lora_printCodingRate(bool from_rx)
{
    uint8_t d = lora.getCodingRate(from_rx);
    printf("CodingRate:");
    switch (d) {
        case 1: printf("4/5 "); break;
        case 2: printf("4/6 "); break;
        case 3: printf("4/7 "); break;
        case 4: printf("4/8 "); break;
        default:
            printf("%d ", d);
            break;
    }
}

void lora_printHeaderMode()
{
    if (lora.getHeaderMode())
        printf("implicit ");
    else
        printf("explicit ");
}

void lora_printBw()
{
    uint8_t bw = lora.getBw();
    
    printf("Bw:");
    if (radio.type == SX1276) {
        switch (lora.RegModemConfig.sx1276bits.Bw) {
            case 0: printf("7.8KHz "); break;
            case 1: printf("10.4KHz "); break;
            case 2: printf("15.6KHz "); break;
            case 3: printf("20.8KHz "); break;
            case 4: printf("31.25KHz "); break;
            case 5: printf("41.7KHz "); break;
            case 6: printf("62.5KHz "); break;
            case 7: printf("125KHz "); break;
            case 8: printf("250KHz "); break;
            case 9: printf("500KHz "); break;
            default: printf("%x ", lora.RegModemConfig.sx1276bits.Bw); break;
        }
    } else if (radio.type == SX1272) {
        switch (lora.RegModemConfig.sx1272bits.Bw) {
            case 0: printf("125KHz "); break;
            case 1: printf("250KHz "); break;
            case 2: printf("500KHz "); break;
            case 3: printf("11b "); break;
        }
    }
}

void lora_printAllBw()
{
    int i, s;
    
    if (radio.type == SX1276) {
        s = lora.RegModemConfig.sx1276bits.Bw;    
        for (i = 0; i < 10; i++ ) {
            lora.RegModemConfig.sx1276bits.Bw = i;
            printf("%d ", i);
            lora_printBw();
            printf("\r\n");
        }
        lora.RegModemConfig.sx1276bits.Bw = s;
    } else if (radio.type == SX1272) {
        s = lora.RegModemConfig.sx1272bits.Bw;    
        for (i = 0; i < 3; i++ ) {
            lora.RegModemConfig.sx1272bits.Bw = i;
            printf("%d ", i);
            lora_printBw();
            printf("\r\n");
        }
        lora.RegModemConfig.sx1272bits.Bw = s;    
    }
}

void lora_printSf()
{
    // spreading factor same between sx127[26]
    printf("sf:%d ", lora.getSf());
}

void lora_printRxPayloadCrcOn()
{
    bool on = lora.getRxPayloadCrcOn();
    //printf("RxPayloadCrcOn:%s ", on ? "on" : "off");
    if (on)
        printf("RxPayloadCrcOn:1 = Tx CRC Enabled\r\n");
    else
        printf("RxPayloadCrcOn:1 = no Tx CRC\r\n");
}

void lora_printTxContinuousMode()
{
    printf("TxContinuousMode:%d ", lora.RegModemConfig2.sx1276bits.TxContinuousMode);    // same for sx1272 and sx1276
}

void lora_printAgcAutoOn()
{
    printf("AgcAutoOn:%d", lora.getAgcAutoOn());
}

void lora_print_dio()
{
    radio.RegDioMapping2.octet = radio.read_reg(REG_DIOMAPPING2);
    printf("DIO5:");
    switch (radio.RegDioMapping2.bits.Dio5Mapping) {
        case 0: printf("ModeReady"); break;
        case 1: printf("ClkOut"); break;
        case 2: printf("ClkOut"); break;
    }
    printf(" DIO4:");
    switch (radio.RegDioMapping2.bits.Dio4Mapping) {
        case 0: printf("CadDetected"); break;
        case 1: printf("PllLock"); break;
        case 2: printf("PllLock"); break;
    }    
    radio.RegDioMapping1.octet = radio.read_reg(REG_DIOMAPPING1);
    printf(" DIO3:");
    switch (radio.RegDioMapping1.bits.Dio3Mapping) {
        case 0: printf("CadDone"); break;
        case 1: printf("ValidHeader"); break;
        case 2: printf("PayloadCrcError"); break;
    }    
    printf(" DIO2:");
    switch (radio.RegDioMapping1.bits.Dio2Mapping) {
        case 0:
        case 1:
        case 2:
            printf("FhssChangeChannel");
            break;
    }    
    printf(" DIO1:");
    switch (radio.RegDioMapping1.bits.Dio1Mapping) {
        case 0: printf("RxTimeout"); break;
        case 1: printf("FhssChangeChannel"); break;
        case 2: printf("CadDetected"); break;
    }    
    printf(" DIO0:");
    switch (radio.RegDioMapping1.bits.Dio0Mapping) {
        case 0: printf("RxDone"); break;
        case 1: printf("TxDone"); break;
        case 2: printf("CadDone"); break;
    }    
    
    printf("\r\n"); 
}

void fsk_print_dio()
{
    radio.RegDioMapping2.octet = radio.read_reg(REG_DIOMAPPING2);
    
    printf("DIO5:");
    switch (radio.RegDioMapping2.bits.Dio5Mapping) {
        case 0: printf("ClkOut"); break;
        case 1: printf("PllLock"); break;
        case 2:
            if (fsk.RegPktConfig2.bits.DataModePacket)
                printf("data");
            else {
                if (radio.RegDioMapping2.bits.MapPreambleDetect)
                    printf("preamble");
                else
                    printf("rssi");
            }
            break;
        case 3: printf("ModeReady"); break;
    }
    
    printf(" DIO4:");
    switch (radio.RegDioMapping2.bits.Dio4Mapping) {
        case 0: printf("temp/eol"); break;
        case 1: printf("PllLock"); break;
        case 2: printf("TimeOut"); break;
        case 3:
            if (fsk.RegPktConfig2.bits.DataModePacket) {
                if (radio.RegDioMapping2.bits.MapPreambleDetect)
                    printf("preamble");
                else
                    printf("rssi");
            } else
                printf("ModeReady");
            break;
    }
    
    radio.RegDioMapping1.octet = radio.read_reg(REG_DIOMAPPING1);
    
    printf(" DIO3:");
    switch (radio.RegDioMapping1.bits.Dio3Mapping) {
        case 0: printf("Timeout"); break;
        case 1:
            if (radio.RegDioMapping2.bits.MapPreambleDetect)
                printf("preamble");
            else
                printf("rssi");
            break;
        case 2: printf("?automode_status?"); break;
        case 3: printf("TempChange/LowBat"); break;
    }
    
    printf(" DIO2:");
    if (fsk.RegPktConfig2.bits.DataModePacket) {
        switch (radio.RegDioMapping1.bits.Dio2Mapping) {
            case 0: printf("FifoFull"); break;
            case 1: printf("RxReady"); break;
            case 2: printf("FifoFull/rx-timeout"); break;
            case 3: printf("FifoFull/rx-syncadrs"); break;
        }
    } else {
        printf("Data");
    }
    
    printf(" DIO1:");
    if (fsk.RegPktConfig2.bits.DataModePacket) {
        switch (radio.RegDioMapping1.bits.Dio1Mapping) {
            case 0: printf("FifoThresh"); break;
            case 1: printf("FifoEmpty"); break;
            case 2: printf("FifoFull"); break;
            case 3: printf("-3-"); break;
        }
    } else {
        switch (radio.RegDioMapping1.bits.Dio1Mapping) {
            case 0: printf("Dclk"); break;
            case 1:
                if (radio.RegDioMapping2.bits.MapPreambleDetect)
                    printf("preamble");
                else
                    printf("rssi");
                break;
            case 2: printf("-2-"); break;
            case 3: printf("-3-"); break;
        }
    }
    
    printf(" DIO0:");
    if (fsk.RegPktConfig2.bits.DataModePacket) {
        switch (radio.RegDioMapping1.bits.Dio0Mapping) {
            case 0: printf("PayloadReady/PacketSent"); break;
            case 1: printf("CrcOk"); break;
            case 2: printf("-2-"); break;
            case 3: printf("TempChange/LowBat"); break;
        }
    } else {
        switch (radio.RegDioMapping1.bits.Dio0Mapping) {
            case 0: printf("SyncAdrs/TxReady"); break;
            case 1:
                if (radio.RegDioMapping2.bits.MapPreambleDetect)
                    printf("preamble");
                else
                    printf("rssi");
                break;
            case 2: printf("RxReady"); break;
            case 3: printf("-3-"); break;
        }
    }
    printf("\r\n"); 
}

void lora_print_status()
{
    uint8_t d;
    
    if (radio.type == SX1276)
        printf("\r\nSX1276 ");
    else if (radio.type == SX1272)
        printf("\r\nSX1272 ");
    
    radio.RegOpMode.octet = radio.read_reg(REG_OPMODE);
    if (!radio.RegOpMode.bits.LongRangeMode) {
        printf("FSK\r\n");
        return;
    }
    
    lora_print_dio();
    printf("LoRa ");
    
    // printing LoRa registers at 0x0d -> 0x3f

    lora.RegModemConfig.octet = radio.read_reg(REG_LR_MODEMCONFIG);
    lora.RegModemConfig2.octet = radio.read_reg(REG_LR_MODEMCONFIG2);

    lora_printCodingRate(false); // false: transmitted coding rate
    lora_printHeaderMode();
    lora_printBw();
    lora_printSf();
    lora_printRxPayloadCrcOn();
    // RegModemStat
    printf("ModemStat:0x%02x\r\n", radio.read_reg(REG_LR_MODEMSTAT));

    // fifo ptrs:
    lora.RegPayloadLength = radio.read_reg(REG_LR_PAYLOADLENGTH);
    lora.RegRxMaxPayloadLength = radio.read_reg(REG_LR_RX_MAX_PAYLOADLENGTH);
    printf("fifoptr=0x%02x txbase=0x%02x rxbase=0x%02x payloadLength=0x%02x maxlen=0x%02x",
        radio.read_reg(REG_LR_FIFOADDRPTR),
        radio.read_reg(REG_LR_FIFOTXBASEADDR),
        radio.read_reg(REG_LR_FIFORXBASEADDR),
        lora.RegPayloadLength,
        lora.RegRxMaxPayloadLength
    );

    lora.RegIrqFlags.octet = radio.read_reg(REG_LR_IRQFLAGS);
    printLoraIrqs_(false);

    lora.RegHopPeriod = radio.read_reg(REG_LR_HOPPERIOD);
    if (lora.RegHopPeriod != 0) {
        printf("\r\nHopPeriod:0x%02x\r\n", lora.RegHopPeriod);
    }

    printf("SymbTimeout:0x%03x ", radio.read_u16(REG_LR_MODEMCONFIG2) & 0x3ff);

    lora.RegPreamble = radio.read_u16(REG_LR_PREAMBLEMSB);
    printf("PreambleLength:%d ", lora.RegPreamble);

    if (radio.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER || radio.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER_SINGLE) {
        d = radio.read_reg(REG_LR_RSSIVALUE);
        printf("rssi:%ddBm ", d-120);
    }

    lora_printTxContinuousMode();

    printf("\r\n");
    lora_printAgcAutoOn();
    if (radio.type == SX1272) {
        printf(" LowDataRateOptimize:%d\r\n", lora.RegModemConfig.sx1272bits.LowDataRateOptimize);
    }

    printf("\r\nHeaderCount:%d PacketCount:%d, ",
        radio.read_u16(REG_LR_RXHEADERCNTVALUE_MSB), radio.read_u16(REG_LR_RXPACKETCNTVALUE_MSB));

    printf("Lora detection threshold:%02x\r\n", radio.read_reg(REG_LR_DETECTION_THRESHOLD));
    lora.RegTest31.octet = radio.read_reg(REG_LR_TEST31);
    printf("detect_trig_same_peaks_nb:%d\r\n", lora.RegTest31.bits.detect_trig_same_peaks_nb);

    if (radio.type == SX1272) {
        lora.RegModemConfig.octet = radio.read_reg(REG_LR_MODEMCONFIG);
        printf("LowDataRateOptimize:%d\r\n", lora.RegModemConfig.sx1272bits.LowDataRateOptimize);
    } else if (radio.type == SX1276) {
        lora.RegModemConfig3.octet = radio.read_reg(REG_LR_MODEMCONFIG3);
        printf("LowDataRateOptimize:%d\r\n", lora.RegModemConfig3.sx1276bits.LowDataRateOptimize);        
    }
    
    printf("\r\n");
    //printf("A %02x\r\n", radio.RegModemConfig2.octet);
}

uint16_t
fsk_get_PayloadLength(void)
{
    fsk.RegPktConfig2.word = radio.read_u16(REG_FSK_PACKETCONFIG2);

    return fsk.RegPktConfig2.bits.PayloadLength;
}

void fsk_printAddressFiltering()
{
    uint8_t FSKRegNodeAdrs, FSKRegBroadcastAdrs;
    
    printf(" AddressFiltering:");
    switch (fsk.RegPktConfig1.bits.AddressFiltering) {
        case 0: printf("off"); break;
        case 1: // NodeAddress
            FSKRegNodeAdrs = radio.read_reg(REG_FSK_NODEADRS);
            printf("NodeAdrs:%02x\n", FSKRegNodeAdrs);
            break;
        case 2: // NodeAddress & BroadcastAddress
            FSKRegNodeAdrs = radio.read_reg(REG_FSK_NODEADRS);
            printf("NodeAdrs:%02x ", FSKRegNodeAdrs);
            FSKRegBroadcastAdrs = radio.read_reg(REG_FSK_BROADCASTADRS);
            printf("BroadcastAdrs:%02x\n", FSKRegBroadcastAdrs );
            break;
        default:
            printf("%d", fsk.RegPktConfig1.bits.AddressFiltering);
            break;
    }
}

void fsk_print_IrqFlags2()
{
    RegIrqFlags2_t RegIrqFlags2;
    
    printf("IrqFlags2: ");
    RegIrqFlags2.octet = radio.read_reg(REG_FSK_IRQFLAGS2);
    if (RegIrqFlags2.bits.FifoFull)
        printf("FifoFull ");
    if (RegIrqFlags2.bits.FifoEmpty)
        printf("FifoEmpty ");
    if (RegIrqFlags2.bits.FifoLevel)
        printf("FifoLevel ");
    if (RegIrqFlags2.bits.FifoOverrun)
        printf("FifoOverrun ");
    if (RegIrqFlags2.bits.PacketSent)
        printf("PacketSent ");
    if (RegIrqFlags2.bits.PayloadReady)
        printf("PayloadReady ");
    if (RegIrqFlags2.bits.CrcOk)
        printf("CrcOk ");
    if (RegIrqFlags2.bits.LowBat)
        printf("LowBat ");
    printf("\r\n");
}

void
fsk_print_status()
{
    //uint16_t s;
    RegIrqFlags1_t RegIrqFlags1;
    
    if (radio.RegOpMode.bits.LongRangeMode) {
        printf("LoRa\r\n");
        return;
    }
    
    if (radio.RegOpMode.bits.ModulationType == 0) {
        printf("FSK ");
        switch (radio.RegOpMode.bits.ModulationShaping) {
            case 1: printf("BT1.0 "); break;
            case 2: printf("BT0.5 "); break;
            case 3: printf("BT0.3 "); break;
        }
    } else if (radio.RegOpMode.bits.ModulationType == 1) {
        printf("OOK ");
    }

    printf("%dbps fdev:%dHz\r\n", fsk.get_bitrate(), fsk.get_tx_fdev_hz());    
    
    fsk.RegPktConfig2.word = radio.read_u16(REG_FSK_PACKETCONFIG2);
    
    fsk_print_dio();
    
    printf("rxbw:%dHz ", fsk.get_rx_bw_hz(REG_FSK_RXBW));
    printf("afcbw:%dHz\r\n", fsk.get_rx_bw_hz(REG_FSK_AFCBW));

    fsk.RegRssiConfig.octet = radio.read_reg(REG_FSK_RSSICONFIG);
    printf("RssiOffset:%ddB smoothing:%dsamples\r\n", fsk.RegRssiConfig.bits.RssiOffset, 1 << (fsk.RegRssiConfig.bits.RssiSmoothing+1));


    fsk.RegSyncConfig.octet = radio.read_reg(REG_FSK_SYNCCONFIG);

    if (fsk.RegPktConfig2.bits.DataModePacket) {
        uint16_t len;
        /* packet mode */
        len = fsk_get_PayloadLength();
        printf("packet RegPayloadLength:0x%03x ", len);

        if (fsk.RegPktConfig2.bits.BeaconOn)
            printf("BeaconOn ");

        fsk.RegFifoThreshold.octet = radio.read_reg(REG_FSK_FIFOTHRESH);
        printf("FifoThreshold:%d TxStartCondition:", fsk.RegFifoThreshold.bits.FifoThreshold);
        if (fsk.RegFifoThreshold.bits.TxStartCondition)
            printf("!FifoEmpty");
        else
            printf("FifoLevel");

        printf("\r\nAutoRestartRxMode:");
        switch (fsk.RegSyncConfig.bits.AutoRestartRxMode) {
            case 0: printf("off "); break;
            case 1: printf("no-pll-wait "); break;
            case 2: printf("pll-wait "); break;
            case 3: printf("3 "); break;
        }
        //...todo

        printf("PreambleSize:%d ", radio.read_u16(REG_FSK_PREAMBLEMSB));

        fsk.RegOokPeak.octet = radio.read_reg(REG_FSK_OOKPEAK);
        if (fsk.RegOokPeak.bits.barker_en)
            printf("barker ");
        if (!fsk.RegOokPeak.bits.BitSyncOn)
            printf("BitSyncOff ");
        //...todo

        fsk.RegPktConfig1.octet = radio.read_reg(REG_FSK_PACKETCONFIG1);
        if (fsk.RegPktConfig1.bits.PacketFormatVariable)
            printf("variable");
        else
            printf("fixed");
        printf("-length\r\ncrc");
        if (fsk.RegPktConfig1.bits.CrcOn) {
            printf("On");
        } else
            printf("Off");
        printf(" crctype:");
        if (fsk.RegPktConfig1.bits.CrCWhiteningType)
            printf("IBM");
        else
            printf("CCITT");
        printf(" dcFree:");
        switch (fsk.RegPktConfig1.bits.DcFree) {
            case 0: printf("none "); break;
            case 1: printf("Manchester "); break;
            case 2: printf("Whitening "); break;
            case 3: printf("reserved "); break;
        }
        fsk_printAddressFiltering();

        printf("\r\n");
        fsk_print_IrqFlags2();
    } else {
        /* continuous mode */
        printf("continuous ");
    }

    fsk.RegPreambleDetect.octet = radio.read_reg(REG_FSK_PREAMBLEDETECT);
    printf("PreambleDetect:");
    if (fsk.RegPreambleDetect.bits.PreambleDetectorOn) {
        printf("size=%d,tol=%d ",
            fsk.RegPreambleDetect.bits.PreambleDetectorSize,
            fsk.RegPreambleDetect.bits.PreambleDetectorTol);
    } else
        printf("Off ");

    printf(" syncsize:%d ", fsk.RegSyncConfig.bits.SyncSize);
    printf(" : %02x ", radio.read_reg(REG_FSK_SYNCVALUE1));
    printf("%02x ", radio.read_reg(REG_FSK_SYNCVALUE2));
    printf("%02x ", radio.read_reg(REG_FSK_SYNCVALUE3));
    printf("%02x ", radio.read_reg(REG_FSK_SYNCVALUE4));
    printf("\r\n");   // end sync config

    fsk.RegAfcFei.octet = radio.read_reg(REG_FSK_AFCFEI);
    printf("afcAutoClear:");
    if (fsk.RegAfcFei.bits.AfcAutoClearOn)
        printf("On");
    else
        printf("OFF");
    printf(" afc:%dHz ", (int)(FREQ_STEP_HZ * radio.read_s16(REG_FSK_AFCMSB)));

    printf("fei:%dHz\r\n", (int)(FREQ_STEP_HZ * radio.read_s16(REG_FSK_FEIMSB)));

    fsk.RegRxConfig.octet = radio.read_reg(REG_FSK_RXCONFIG);
    printf("RxTrigger:");
    switch (fsk.RegRxConfig.bits.RxTrigger) {
        case 0: printf("none "); break;
        case 1: printf("rssi "); break;
        case 6: printf("preamble "); break;
        case 7: printf("both "); break;
        default: printf("-%d- ", fsk.RegRxConfig.bits.RxTrigger); break;
    }
    printf("AfcAuto:");
    if (fsk.RegRxConfig.bits.AfcAutoOn)
        printf("On ");
    else
        printf("OFF ");
    if (!fsk.RegRxConfig.bits.AgcAutoOn) {
        radio.RegLna.octet = radio.read_reg(REG_LNA);
        printf("AgcAutoOff:G%d ", radio.RegLna.bits.LnaGain);
    }

    fsk.RegTimerResol.octet = radio.read_reg(REG_FSK_TIMERRESOL);
    if (fsk.RegTimerResol.bits.hlm_started)
        printf("hlm_started ");
    else
        printf("hlm_stopped ");

    fsk.RegRssiThresh = radio.read_reg(REG_FSK_RSSITHRESH);
    printf("rssiThreshold:-%.1f@%02x ", fsk.RegRssiThresh / 2.0, REG_FSK_RSSITHRESH);

    radio.RegOpMode.octet = radio.read_reg(REG_OPMODE);
    if (radio.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER ||
        radio.RegOpMode.bits.Mode == RF_OPMODE_SYNTHESIZER_RX)
    {
        printf("rssi:-%.1f ", radio.read_reg(REG_FSK_RSSIVALUE) / 2.0);
    }

    fsk.RegSeqConfig1.octet = radio.read_reg(REG_FSK_SEQCONFIG1);
    printf("\r\nsequencer: ");
    printf("FromStart:");
    switch (fsk.RegSeqConfig1.bits.FromStart) {
        case 0:
            printf("lowPowerSelection-");
            if (fsk.RegSeqConfig1.bits.LowPowerSelection)
                printf("idle");
            else
                printf("sequencerOff");
            break;
        case 1: printf("rx"); break;
        case 2: printf("tx"); break;
        case 3: printf("tx on fifolevel"); break;
    }
    printf(" lowPowerSelection:");
    if (fsk.RegSeqConfig1.bits.LowPowerSelection)
        printf("idle");
    else
        printf("SequencerOff");
    if (fsk.RegSeqConfig1.bits.FromStart != 0 && 
        fsk.RegSeqConfig1.bits.LowPowerSelection != 0)
    {   // if sequencer enabled:
        printf("\r\nsequencer: IdleMode:");
        if (fsk.RegSeqConfig1.bits.IdleMode)
            printf("Sleep");
        else
            printf("standby");
        printf("\r\nsequencer: FromIdle to:");
        if (fsk.RegSeqConfig1.bits.FromIdle)
            printf("rx");
        else
            printf("tx");
        printf("\r\nsequencer: FromTransmit to:");
        if (fsk.RegSeqConfig1.bits.FromTransmit)
            printf("rx-on-PacketSent");
        else {
            printf("lowPowerSelection-");
            if (fsk.RegSeqConfig1.bits.LowPowerSelection)
                printf("idle");
            else
                printf("SequencerOff");
            printf("-on-PacketSent");
        }
        fsk.RegSeqConfig2.octet = radio.read_reg(REG_FSK_SEQCONFIG2);
        printf("\r\nsequencer: FromReceive:");
        switch (fsk.RegSeqConfig2.bits.FromReceive) {
            case 1: printf("PacketRecevied on PayloadReady"); break;
            case 2: 
                printf("lowPowerSelection-");
                if (fsk.RegSeqConfig1.bits.LowPowerSelection)
                    printf("idle");
                else
                    printf("SequencerOff");
                printf("-on-payloadReady");
                break;
            case 3: printf("PacketRecevied-on-CrcOk"); break;
            case 4: printf("SequencerOff-on-Rssi"); break;
            case 5: printf("SequencerOff-on-SyncAddress"); break;
            case 6: printf("SequencerOff-PreambleDetect"); break;
            default: printf("-%d-", fsk.RegSeqConfig2.bits.FromReceive); break;
        }
        printf("\r\nsequencer: FromRxTimeout:");
        switch (fsk.RegSeqConfig2.bits.FromRxTimeout) {
            case 0: printf("rx"); break;
            case 1: printf("tx"); break;
            case 2:
                printf("lowPowerSelection-");
                if (fsk.RegSeqConfig1.bits.LowPowerSelection)
                    printf("idle");
                else
                    printf("SequencerOff");
                break;
            case 3: printf("SequencerOff"); break;
        }
        printf("\r\nsequencer: FromPacketReceived to:");
        switch (fsk.RegSeqConfig2.bits.FromPacketReceived) {
            case 0: printf("SequencerOff"); break;
            case 1: printf("tx on FifoEmpty"); break;
            case 2:
                printf("lowPowerSelection-");
                if (fsk.RegSeqConfig1.bits.LowPowerSelection)
                printf("idle");
                else
                printf("sequencerOff");
                break;
            case 3: printf("rx via fs"); break;
            case 4: printf("rx"); break;
        }

        fsk.RegTimerResol.octet = radio.read_reg(REG_FSK_TIMERRESOL);
        printf("\r\nsequencer: timer1:");
        switch (fsk.RegTimerResol.bits.timer1_resol) {
            case 0: printf("off"); break;
            case 1: printf("%dus", radio.read_reg(REG_FSK_TIMER1COEF) * 64); break;
            case 2: printf("%.1fms", radio.read_reg(REG_FSK_TIMER1COEF) * 4.1); break;
            case 3: printf("%.1fs", radio.read_reg(REG_FSK_TIMER1COEF) * 0.262); break;
        }

        printf(" timer2:");
        switch (fsk.RegTimerResol.bits.timer2_resol) {
            case 0: printf("off"); break;
            case 1: printf("%dus", radio.read_reg(REG_FSK_TIMER2COEF) * 64); break;
            case 2: printf("%.1fms", radio.read_reg(REG_FSK_TIMER2COEF) * 4.1); break;
            case 3: printf("%.1fs", radio.read_reg(REG_FSK_TIMER2COEF) * 0.262); break;
        }
    } // ..if sequencer enabled

    printf("\r\nIrqFlags1:");
    RegIrqFlags1.octet = radio.read_reg(REG_FSK_IRQFLAGS1);
    if (RegIrqFlags1.bits.ModeReady)
        printf("ModeReady ");
    if (RegIrqFlags1.bits.RxReady)
        printf("RxReady ");
    if (RegIrqFlags1.bits.TxReady)
        printf("TxReady ");
    if (RegIrqFlags1.bits.PllLock)
        printf("PllLock ");
    if (RegIrqFlags1.bits.Rssi)
        printf("Rssi ");
    if (RegIrqFlags1.bits.Timeout)
        printf("Timeout ");
    if (RegIrqFlags1.bits.PreambleDetect)
        printf("PreambleDetect ");
    if (RegIrqFlags1.bits.SyncAddressMatch)
        printf("SyncAddressMatch ");

    printf("\r\n");

/* TODO    if (!SX1272FSK->RegPktConfig1.bits.PacketFormatVariable) { // if fixed-length packet format:
        s = fsk_get_PayloadLength();
        if (s > FSK_LARGE_PKT_THRESHOLD)
            flags.fifo_flow_ctl = 1;
        else
            flags.fifo_flow_ctl = 0;
    }*/

    fsk.RegImageCal.octet = radio.read_reg(REG_FSK_IMAGECAL);
    if (fsk.RegImageCal.bits.TempMonitorOff) {
        printf("TempMonitorOff[\r0m\n");
    } else {
        printf("TempThreshold:");
        switch (fsk.RegImageCal.bits.TempThreshold) {
            case 0: printf("5C"); break;
            case 1: printf("10C"); break;
            case 2: printf("15C"); break;
            case 3: printf("20C"); break;
        }
        printf("\r\n");
    }
    if (fsk.RegImageCal.bits.ImageCalRunning)
        printf("ImageCalRunning[\r0m\n");

/*    printf("flags.fifo_flow_ctl:%d pktidx:%d rx_pktlen:%d", flags.fifo_flow_ctl, pktidx, rx_pktlen);
    printf("\n");

    //printf("DIO0_PIN:%d\n", digitalRead(DIO0_PIN));
    printf("pkt_buf_len=%d remaining=%d\n", pk*/
}

void printOpMode()
{
    radio.RegOpMode.octet = radio.read_reg(REG_OPMODE);
    switch (radio.RegOpMode.bits.Mode) {
        case RF_OPMODE_SLEEP: printf("sleep"); break;
        case RF_OPMODE_STANDBY: printf("stby"); break;
        case RF_OPMODE_SYNTHESIZER_TX: printf("fstx"); break;
        case RF_OPMODE_TRANSMITTER: printf("tx"); break;
        case RF_OPMODE_SYNTHESIZER_RX: printf("fsrx"); break;
        case RF_OPMODE_RECEIVER: printf("rx"); break;
        case 6:
            if (radio.RegOpMode.bits.LongRangeMode)
                printf("rxs");
            else
                printf("-6-");
            break;  // todo: different lora/fsk
        case 7:
            if (radio.RegOpMode.bits.LongRangeMode)
                printf("cad");
            else
                printf("-7-");
            break;  // todo: different lora/fsk
    }
}

void
printPa()
{
    radio.RegPaConfig.octet = radio.read_reg(REG_PACONFIG);
    if (radio.RegPaConfig.bits.PaSelect) {
        float output_dBm = 17 - (15-radio.RegPaConfig.bits.OutputPower);
        printf(" PABOOST OutputPower=%.1fdBm", output_dBm);
    } else {
        float pmax = (0.6*radio.RegPaConfig.bits.MaxPower) + 10.8;
        float output_dBm = pmax - (15-radio.RegPaConfig.bits.OutputPower);
        printf(" RFO pmax=%.1fdBm OutputPower=%.1fdBm", pmax, output_dBm);
    }
}

void /* things always present, whether lora or fsk */
common_print_status()
{
    printf("version:0x%02x %.3fMHz ", radio.read_reg(REG_VERSION), radio.get_frf_MHz());
    printOpMode();

    printPa();

    radio.RegOcp.octet = radio.read_reg(REG_OCP);
    if (radio.RegOcp.bits.OcpOn) {
        int imax = 0;
        if (radio.RegOcp.bits.OcpTrim < 16)
            imax = 45 + (5 * radio.RegOcp.bits.OcpTrim);
        else if (radio.RegOcp.bits.OcpTrim < 28)
            imax = -30 + (10 * radio.RegOcp.bits.OcpTrim);
        else
            imax = 240;
        printf(" OcpOn %dmA ", imax);
    } else
        printf(" OcpOFF ");

    printf("\r\n");

}

void print_rx_buf(int len)
{
    int i;

    printf("000:");
    for (i = 0; i < len; i++) {
        //printf("(%d)%02x ", i % 16, rx_buf[i]);
        printf("%02x ", radio.rx_buf[i]);
        if (i % 16 == 15 && i != len-1)
            printf("\r\n%03d:", i+1);

    }
    printf("\r\n");
}

void
service_radio()
{
    service_action_e act;
    
    if (radio.RegOpMode.bits.LongRangeMode) {

        act = lora.service();
    
        switch (act) {
            case SERVICE_READ_FIFO:
                float dbm;
                if (app == APP_NONE) {     
                    printLoraIrqs_(false);
                    if (lora.RegHopPeriod > 0) {
                        lora.RegHopChannel.octet = radio.read_reg(REG_LR_HOPCHANNEL);
                        printf("HopCH:%d ", lora.RegHopChannel.bits.FhssPresentChannel);
                    }
                    lora_printCodingRate(true);  // true: of received packet
                    dbm = lora.get_pkt_rssi();
                    printf(" crc%s %.1fdB  %.1fdBm\r\n",
                        lora.RegHopChannel.bits.RxPayloadCrcOn ? "On" : "OFF",
                        lora.RegPktSnrValue / 4.0,
                        dbm
                    );
                    print_rx_buf(lora.RegRxNbBytes);
                } else if (app == APP_CHAT) {
                    if (lora.RegHopChannel.bits.RxPayloadCrcOn) {
                        if (lora.RegIrqFlags.bits.PayloadCrcError)
                            printf("crcError\r\n");
                        else {
                            int n = lora.RegRxNbBytes;
                            radio.rx_buf[n++] = '\r';
                            radio.rx_buf[n++] = '\n';
                            radio.rx_buf[n] = 0; // null terminate
                            printf((char *)radio.rx_buf);
                        }
                    } else
                        printf("crcOff\r\n");
                        
                    // clear Irq flags
                    radio.write_reg(REG_LR_IRQFLAGS, lora.RegIrqFlags.octet);
                    // should still be in receive mode
                }
                break;
            case SERVICE_TX_DONE:
                if (app == APP_CHAT) {
                    lora.start_rx();
                }
                break;
            case SERVICE_ERROR:
                printf("error\r\n");
                break;
        } // ...switch (act)
    } else {
        /* FSK: */
        act = fsk.service();
        
         switch (act) {
             case SERVICE_READ_FIFO:
                if (app == APP_CHAT) {
                    int n = fsk.rx_buf_length;
                    radio.rx_buf[n++] = '\r';
                    radio.rx_buf[n++] = '\n';
                    radio.rx_buf[n] = 0; // null terminate
                    printf((char *)radio.rx_buf);                    
                } else {
                    int i;
                    if (fsk.RegRxConfig.bits.AfcAutoOn)
                        printf("%dHz ", (int)(FREQ_STEP_HZ * fsk.RegAfcValue));
                    printf("%d: ", fsk.rx_buf_length);
                    for (i = 0; i < fsk.rx_buf_length; i++)
                        printf("%02x ", radio.rx_buf[i]);
                    printf("\r\n");
                }
                break;
            case SERVICE_TX_DONE:
                if (app == APP_CHAT) {
                    fsk.start_rx();
                }
                break;                
         } // ...switch (act)
    }
}

int get_kbd_str(char* buf, int size)
{
    char c;
    int i;
    static int prev_len;
    
    for (i = 0;;) {
        if (pc.readable()) {
            c = pc.getc();
            if (c == 8 && i > 0) {
                pc.putc(8);
                pc.putc(' ');
                pc.putc(8);
                i--;
            } else if (c == '\r') {
                if (i == 0) {
                    return prev_len; // repeat previous
                } else {
                    buf[i] = 0; // null terminate
                    prev_len = i;
                    return i;
                }
            } else if (c == 3) {
                // ctrl-C abort
                return -1;
            } else if (i < size) {
                buf[i++] = c;
                pc.putc(c);
            }
        } else {
            service_radio();
        }
    } // ...for()
}

void
console_chat()
{
    int i, len = get_kbd_str(pcbuf, sizeof(pcbuf));
    if (len < 0) {
        printf("chat abort\r\n");
        app = APP_NONE;
        return;
    } else {
        for (i = 0; i < len; i++)
            radio.tx_buf[i] = pcbuf[i];
        if (radio.RegOpMode.bits.LongRangeMode) {
            lora.RegPayloadLength = len;
            radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength);
            lora.start_tx(len);
        } else {
            fsk.start_tx(len);
        }
        printf("\r\n");
    }
}

void
console()
{
    int len, i;
    uint32_t ui;
    uint8_t a, d;
    static uint16_t fsk_tx_length;
        
    len = get_kbd_str(pcbuf, sizeof(pcbuf));
    if (len < 0) {
        printf("abort\r\n");
        return;
    }
    
    printf("\r\n");
    if (len == 1) {
        switch (pcbuf[0]) {
            case 'i':
                printf("init\r\n");
                radio.init();
                if (!radio.RegOpMode.bits.LongRangeMode) {
                    fsk.init();   // put FSK modem to some functioning default
                } else {
                    // lora configuration is more simple
                }
                break;
            case 'h':
                printf("hw_reset()\r\n");
                radio.hw_reset();
                break;
            case 'R':
                // read all registers
                for (a = 1; a < 0x71; a++) {
                    d = radio.read_reg(a);
                    //update_shadow_regs(selected_radio, a, d); 
                    printf("%02x: %02x\r\n", a, d);
                }
                break;
            case 'T':
                if (radio.RegOpMode.bits.LongRangeMode) {
                    lora.RegModemConfig2.octet = radio.read_reg(REG_LR_MODEMCONFIG2);
                    //printf("a %02x\r\n", radio.RegModemConfig2.octet);
                    lora.RegModemConfig2.sx1276bits.TxContinuousMode ^= 1;   // same for sx1272 and sx1276
                    //printf("b %02x\r\n", radio.RegModemConfig2.octet);
                    radio.write_reg(REG_LR_MODEMCONFIG2, lora.RegModemConfig2.octet);
                    lora.RegModemConfig2.octet = radio.read_reg(REG_LR_MODEMCONFIG);
                    //printf("c %02x\r\n", radio.RegModemConfig2.octet);
                    lora_printTxContinuousMode();
                    printf("\r\n");
                }
                break;
            case 'C':
                if (radio.RegOpMode.bits.LongRangeMode) {
                    lora.setRxPayloadCrcOn(!lora.getRxPayloadCrcOn());
                    lora_printRxPayloadCrcOn();
                } else {
                    printf("CrcOn:");
                    fsk.RegPktConfig1.bits.CrcOn ^= 1;
                    radio.write_reg(REG_FSK_PACKETCONFIG1, fsk.RegPktConfig1.octet);
                    if (fsk.RegPktConfig1.bits.CrcOn)
                        printf("On\r\n");
                    else
                        printf("Off\r\n");
                    if (fsk.RegPktConfig2.bits.DataModePacket && radio.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER) {
                        fsk.config_dio0_for_pktmode_rx();
                    }
                }
                printf("\r\n");
                break;
            case 'B':
                radio.RegPaConfig.bits.PaSelect ^= 1;
                radio.write_reg(REG_PACONFIG, radio.RegPaConfig.octet);
                printPa();
                printf("\r\n");
                break;
            case 'L':  
                if (radio.RegOpMode.bits.LongRangeMode)
                    fsk.enable();
                else
                    lora.enable();

                radio.RegOpMode.octet = radio.read_reg(REG_OPMODE);
                if (radio.RegOpMode.bits.LongRangeMode)
                    printf("LoRa\r\n");
                else
                    printf("FSK\r\n");                
                break;
            case 's':
                if (!radio.RegOpMode.bits.LongRangeMode) {
                    fsk.RegFifoThreshold.bits.TxStartCondition ^= 1;
                    radio.write_reg(REG_FSK_FIFOTHRESH, fsk.RegFifoThreshold.octet);
                    printf("TxStartCondition:");
                    if (fsk.RegFifoThreshold.bits.TxStartCondition)
                        printf("!FifoEmpty\r\n");
                    else
                        printf("FifoLevel\r\n");                    
                }
                break;
            case 'f':
                if (!radio.RegOpMode.bits.LongRangeMode) {
                    printf("PacketFormat:");
                    fsk.RegPktConfig1.bits.PacketFormatVariable ^= 1;
                    radio.write_reg(REG_FSK_PACKETCONFIG1, fsk.RegPktConfig1.octet);
                    if (fsk.RegPktConfig1.bits.PacketFormatVariable)
                        printf("variable\r\n");
                    else
                        printf("fixed\r\n");
                    /*if (radio.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER)
                        reset_flow();*/
                }
                break;
            case 'E':
                if (!radio.RegOpMode.bits.LongRangeMode) {
                    RegIrqFlags2_t RegIrqFlags2;
                    RegIrqFlags2.octet = radio.read_reg(REG_FSK_IRQFLAGS2);
                    while (!RegIrqFlags2.bits.FifoEmpty) {
                        if (pc.readable())
                            break;
                        printf("%02x\r\n", radio.read_reg(REG_FIFO));
                        RegIrqFlags2.octet = radio.read_reg(REG_FSK_IRQFLAGS2);
                    }
                }
                break;
            case 'A':
                if (!radio.RegOpMode.bits.LongRangeMode) {
                    fsk.RegRxConfig.bits.AfcAutoOn ^= 1;
                    radio.write_reg(REG_FSK_RXCONFIG, fsk.RegRxConfig.octet);
                    printf("AfcAuto:");
                    if (fsk.RegRxConfig.bits.AfcAutoOn)
                        printf("On\r\n");
                    else
                        printf("OFF\r\n");
                    break;
                }
                break;
            case '?':
                printf("L           toggle LongRangeMode/FSK\r\n");
                printf("i           radio_init\r\n");
                printf("h           hw_reset\r\n");
                printf("tx[%%d]    transmit\r\n");
                printf("rx          receive\r\n");   
                printf("C           toggle crcOn\r\n");
                printf("op[%%d]    get/set output power\r\n");
                printf("d[0-5]      change DIO pin assignment\r\n");
                printf("frf[%%f}   get/set operating frequency (MHz)\r\n");
                if (radio.RegOpMode.bits.LongRangeMode) {
                    printf("pl[%%d]    LORA get/set RegPayloadLength\r\n");
                    printf("cr[1234]    LORA set coding rate \r\n");
                    printf("bw[%%d]    LORA get/set bandwidth\r\n");
                    printf("sf[%%d]    LORA get/set spreading factor\r\n");
                    printf("T           LORA toggle TxContinuousMode\r\n");
                    printf("hp[%%d]    LORA get/set hop period\r\n");
                    printf("hm          LORA toggle explicit/explicit header mode\r\n");
                } else {
                    printf("bw[a][%%d] FSK get-set rxbw (bwa=afcbw)\r\n");
                    printf("br[%%d]    FSK get-set bitrate\r\n");
                    printf("fdev[%%d]    FSK get-set TX frequency deviation (hz)\r\n");
                    printf("rt          FSK change RxTrigger\r\n");
                    printf("pd          FSK enable/disable preamble detector\r\n");
                    printf("pt          FSK get-set PreambleDetectorTol\r\n");
                    printf("ss[%%d]    FSK get-set SyncSize\r\n");
                    printf("S[%%x]     FSK get-set sync word\r\n");
                    printf("s           FSK toggle TxStartCondition\r\n");
                    printf("f           FSK toggle PacketFormat fixed-variable\r\n");
                    printf("E           FSK empty out the fifo\r\n");
                    printf("ac          FSK AfcClear\r\n");
                    printf("A           FSK toggle AfcAutoOn\r\n");
                    printf("mp          FSK toggle MapPreambleDetect\r\n");
                    printf("ar          FSK change AutoRestartRxMode\r\n");
                    printf("alc          FSK toggle AfcAutoClearOn\r\n");
                    printf("pre[%%d}    FSK get-set TX preamble length\r\n");
                }
                break;
            case '.':
                if (radio.RegOpMode.bits.LongRangeMode)
                    lora_print_status();
                else
                    fsk_print_status();
                common_print_status();
                break;
        } // ...switch (pcbuf[0])
    } else {
        if (pcbuf[0] == 't' && pcbuf[1] == 'x') { // TX
            if (radio.RegOpMode.bits.LongRangeMode) {
                if (pcbuf[2] >= '0' && pcbuf[2] <= '9') {
                    sscanf(pcbuf+2, "%d", &i);
                    lora.RegPayloadLength = i;
                }
                tx_cnt++;
                for (i = 0; i < lora.RegPayloadLength; i++)
                    radio.tx_buf[i] = tx_cnt;
                lora.start_tx(lora.RegPayloadLength);
            } else {    // FSK:
                if (pcbuf[2] >= '0' && pcbuf[2] <= '9') {
                    sscanf(pcbuf+2, "%d", &i);
                    fsk_tx_length = i;
                }
                if (radio.RegOpMode.bits.Mode != RF_OPMODE_TRANSMITTER) { // if not already busy transmitting
                    tx_cnt++;
                    for (i = 0; i < fsk_tx_length; i++) {
                        radio.tx_buf[i] = tx_cnt;
                    }
                    fsk.start_tx(fsk_tx_length);
                }
            }
        } else if (pcbuf[0] == 'h' && pcbuf[1] == 'p' && radio.RegOpMode.bits.LongRangeMode) {
            if (pcbuf[2] >= '0' && pcbuf[2] <= '9') {
                sscanf(pcbuf+2, "%d", &i);
                lora.RegHopPeriod = i;
                radio.write_reg(REG_LR_HOPPERIOD, lora.RegHopPeriod);
                if (radio.RegDioMapping1.bits.Dio1Mapping != 1) {
                    radio.RegDioMapping1.bits.Dio1Mapping = 1;
                    radio.write_reg(REG_DIOMAPPING1, radio.RegDioMapping1.octet);
                }
            }
            lora.RegHopPeriod = radio.read_reg(REG_LR_HOPPERIOD);
            printf("HopPeriod:0x%02x\r\n", lora.RegHopPeriod);
        } else if (pcbuf[0] == 'r' && pcbuf[1] == 't' && !radio.RegOpMode.bits.LongRangeMode) {
            printf("RxTrigger:");
            switch (fsk.RegRxConfig.bits.RxTrigger) {
                case 0: fsk.RegRxConfig.bits.RxTrigger = 1;
                    printf("rssi\r\n");
                    break;
                case 1: fsk.RegRxConfig.bits.RxTrigger = 6;
                    printf("preamble\r\n");
                    break;
                case 6: fsk.RegRxConfig.bits.RxTrigger = 7;
                    printf("both\r\n");
                    break;
                case 7: fsk.RegRxConfig.bits.RxTrigger = 0;
                    printf("none\r\n");
                    break;
                default: fsk.RegRxConfig.bits.RxTrigger = 0;
                    printf("none\r\n");
                    break;
                }
            radio.write_reg(REG_FSK_RXCONFIG, fsk.RegRxConfig.octet);            
        } else if (pcbuf[0] == 'r' && pcbuf[1] == 'x') { // RX
            if (radio.RegOpMode.bits.LongRangeMode)
                lora.start_rx();
            else
                fsk.start_rx();
        } else if (pcbuf[0] == 'r' && pcbuf[1] == ' ') { // read single register
            sscanf(pcbuf+2, "%x", &i);
            printf("%02x: %02x\r\n", i, radio.read_reg(i));
        } else if (pcbuf[0] == 'w' && pcbuf[1] == ' ') { // write single register
            sscanf(pcbuf+2, "%x %x", &i, &len);
            radio.write_reg(i, len);
            printf("%02x: %02x\r\n", i, radio.read_reg(i));
        } else if (pcbuf[0] == 'b' && pcbuf[1] == '8') {
            printf("SCL:");
            switch (pcbuf[2]) {
                case '0':
                    pb8.output();
                    pb8 = 0;
                    printf("lo");
                    break;
                case '1':
                    pb8.output();
                    pb8 = 1;
                    printf("hi");
                    break;                    
                case 'z':
                    pb8.input();
                    printf("z");
                    break;                    
            }
            printf("\n");
        } else if (pcbuf[0] == 'b' && pcbuf[1] == '9') {
            printf("SDA:");
            switch (pcbuf[2]) {
                case '0':
                    pb9.output();
                    pb9 = 0;
                    printf("lo");
                    break;
                case '1':
                    pb9.output();
                    pb9 = 1;
                    printf("hi");
                    break;                    
                case 'z':
                    pb9.input();
                    printf("z");
                    break;                    
            }
            printf("\n");                      
        } /*else if (pcbuf[0] == 'm' && pcbuf[1] == 'm') {
            mma8451q.try_read();
        } else if (pcbuf[0] == 'm' && pcbuf[1] == 'p' && pcbuf[2] == 'l') {
            mpl3115a2.try_read();
        } else if (pcbuf[0] == '9' && pcbuf[1] == '5') {
            sx9500.try_read();
        } */else if (pcbuf[0] == 'm' && pcbuf[1] == 'p' && !radio.RegOpMode.bits.LongRangeMode) {
            radio.RegDioMapping2.bits.MapPreambleDetect ^= 1;
            radio.write_reg(REG_DIOMAPPING2, radio.RegDioMapping2.octet);
            printf("MapPreambleDetect:");
            if (radio.RegDioMapping2.bits.MapPreambleDetect)
                printf("preamble\r\n");
            else
                printf("rssi\r\n");
        } else if (pcbuf[0] == 'o' && pcbuf[1] == 'p') {
            if (pcbuf[2] >= '0' && pcbuf[2] <= '9') {
                sscanf(pcbuf+2, "%d", &i);
                radio.RegPaConfig.bits.OutputPower = i;
                radio.write_reg(REG_PACONFIG, radio.RegPaConfig.octet);
            }
            radio.RegPaConfig.octet = radio.read_reg(REG_PACONFIG);
            printf("OutputPower:%d\r\n", radio.RegPaConfig.bits.OutputPower);
        } else if (pcbuf[0] == 'c' && pcbuf[1] == 'r' && radio.RegOpMode.bits.LongRangeMode) {
            if (pcbuf[2] >= '0' && pcbuf[2] <= '9')
                lora.setCodingRate(pcbuf[2] - '0');
             lora.RegModemConfig.octet = radio.read_reg(REG_LR_MODEMCONFIG);
             lora_printCodingRate(false);    // false: transmitted
             printf("\r\n");
        } else if (pcbuf[0] == 'h' && pcbuf[1] == 'm' && radio.RegOpMode.bits.LongRangeMode) {    // toggle implicit/explicit
            lora.setHeaderMode(!lora.getHeaderMode());
            lora.RegModemConfig.octet = radio.read_reg(REG_LR_MODEMCONFIG);
            lora_printHeaderMode();
            printf("\r\n");
        } else if (pcbuf[0] == 'a' && pcbuf[1] == 'l' && !radio.RegOpMode.bits.LongRangeMode) {
            fsk.RegAfcFei.bits.AfcAutoClearOn ^= 1;
            printf("AfcAutoClearOn: ");
            radio.write_reg(REG_FSK_AFCFEI, fsk.RegAfcFei.octet);
            if (fsk.RegAfcFei.bits.AfcAutoClearOn)
                printf("ON\r\n");
            else
                printf("off\r\n");
        } else if (pcbuf[0] == 'a' && pcbuf[1] == 'r' && !radio.RegOpMode.bits.LongRangeMode) {
            fsk.RegSyncConfig.bits.AutoRestartRxMode++;
            radio.write_reg(REG_FSK_SYNCCONFIG, fsk.RegSyncConfig.octet);
            fsk.RegSyncConfig.octet = radio.read_reg(REG_FSK_SYNCCONFIG);
            printf("AutoRestartRxMode:");
            switch (fsk.RegSyncConfig.bits.AutoRestartRxMode) {
                case 0: printf("off "); break;
                case 1: printf("no-pll-wait "); break;
                case 2: printf("pll-wait "); break;
                case 3: printf("3 "); break;
            }
            printf("\r\n");            
        } else if (pcbuf[0] == 'a' && pcbuf[1] == 'c' && !radio.RegOpMode.bits.LongRangeMode) {
            printf("clear afc: ");
            fsk.RegAfcFei.bits.AfcClear = 1;
            radio.write_reg(REG_FSK_AFCFEI, fsk.RegAfcFei.octet);
            fsk.RegAfcFei.bits.AfcClear = 0; 
            printf("%dHz\r\n", (int)(FREQ_STEP_HZ * radio.read_s16(REG_FSK_AFCMSB)));
        } else if (pcbuf[0] == 'b' && pcbuf[1] == 'r' && !radio.RegOpMode.bits.LongRangeMode) {
            if (pcbuf[2] >= '0' && pcbuf[2] <= '9') {
                sscanf(&pcbuf[2], "%d", &i);
                fsk.set_bitrate(i);
            }
            printf("%dbps\r\n", fsk.get_bitrate());             
        } else if (pcbuf[0] == 'b' && pcbuf[1] == 'w') {
            if (radio.RegOpMode.bits.LongRangeMode) {
                if (pcbuf[2] >= '0' && pcbuf[2] <= '9') {
                    radio.set_opmode(RF_OPMODE_STANDBY);
                    sscanf(&pcbuf[2], "%d", &i);
                    lora.setBw(i);
                } else
                    lora_printAllBw();
                lora.RegModemConfig.octet = radio.read_reg(REG_LR_MODEMCONFIG);
                printf("current ");
                lora_printBw();
                printf("\r\n");
            } else { // FSK:
                if (pcbuf[2] == 'a') {
                    if (pcbuf[3] >= '0' && pcbuf[3] <= '9') {
                        radio.set_opmode(RF_OPMODE_STANDBY);
                        sscanf(&pcbuf[3], "%d", &i);
                        fsk.set_rx_dcc_bw_hz(i, 1);
                    }
                    printf("afcbw:%dHz\r\n", fsk.get_rx_bw_hz(REG_FSK_AFCBW));
                } else {
                    if (pcbuf[2] >= '0' && pcbuf[2] <= '9') {
                        radio.set_opmode(RF_OPMODE_STANDBY);
                        sscanf(&pcbuf[2], "%d", &i);
                        fsk.set_rx_dcc_bw_hz(i, 0);
                    }
                    printf("rxbw:%dHz\r\n", fsk.get_rx_bw_hz(REG_FSK_RXBW));
                }
            }
        } else if (pcbuf[0] == 'v' && pcbuf[1] == 'h') {
            lora.poll_vh ^= 1;
            printf("poll_vh:%d\r\n", lora.poll_vh);
        } else if (pcbuf[0] == 'S' && !radio.RegOpMode.bits.LongRangeMode) {
            if (pcbuf[1] == '0') {
                sscanf(pcbuf+1, "%x", &ui);
                if (ui < 0x100) {
                    fsk.RegSyncConfig.bits.SyncSize = 0;
                    radio.write_reg(REG_FSK_SYNCVALUE1, ui);
                } else if (ui < 0x10000) {
                    fsk.RegSyncConfig.bits.SyncSize = 1;
                    radio.write_reg(REG_FSK_SYNCVALUE2, ui & 0xff);
                    radio.write_reg(REG_FSK_SYNCVALUE1, ui >> 8);
                } else if (ui < 0x1000000) {
                    fsk.RegSyncConfig.bits.SyncSize = 2;
                    radio.write_reg(REG_FSK_SYNCVALUE3, ui & 0xff);
                    radio.write_reg(REG_FSK_SYNCVALUE2, (ui >> 8) & 0xff);
                    radio.write_reg(REG_FSK_SYNCVALUE1, ui >> 16);                              
                } else {
                    fsk.RegSyncConfig.bits.SyncSize = 3;
                    radio.write_reg(REG_FSK_SYNCVALUE4, ui & 0xff);
                    radio.write_reg(REG_FSK_SYNCVALUE3, (ui >> 8) & 0xff);
                    radio.write_reg(REG_FSK_SYNCVALUE2, (ui >> 16) & 0xff);
                    radio.write_reg(REG_FSK_SYNCVALUE1, ui >> 24);                       
                }
                radio.write_reg(REG_FSK_SYNCCONFIG, fsk.RegSyncConfig.octet);
            }
            fsk.RegSyncConfig.octet = radio.read_reg(REG_FSK_SYNCCONFIG);
            printf("%d: ", fsk.RegSyncConfig.bits.SyncSize);
            for (i = 0; i <= fsk.RegSyncConfig.bits.SyncSize; i++)
                printf("%02x ", radio.read_reg(REG_FSK_SYNCVALUE1+i));
            printf("\r\n");
        } else if (pcbuf[0] == 's' && pcbuf[1] == 's' && !radio.RegOpMode.bits.LongRangeMode) {
            if (pcbuf[2] >= '0' && pcbuf[2] <= '9') {
                sscanf(pcbuf+2, "%d", &i);
                fsk.RegSyncConfig.bits.SyncSize = i;
                radio.write_reg(REG_FSK_SYNCCONFIG, fsk.RegSyncConfig.octet);
            }
            fsk.RegSyncConfig.octet = radio.read_reg(REG_FSK_SYNCCONFIG);
            printf("SyncSize:%d\r\n", fsk.RegSyncConfig.bits.SyncSize);
        } else if (pcbuf[0] == 's' && pcbuf[1] == 'f' && radio.RegOpMode.bits.LongRangeMode) {
            if (pcbuf[2] >= '0' && pcbuf[2] <= '9') {
                sscanf(pcbuf+2, "%d", &i);
                lora.setSf(i);
                if (i == 6 && !lora.getHeaderMode()) {
                    printf("SF6: to implicit header mode\r\n");
                    lora.setHeaderMode(true);
                }
            }
            lora.RegModemConfig2.octet = radio.read_reg(REG_LR_MODEMCONFIG2);
            lora_printSf();
            printf("\r\n");
        } else if (pcbuf[0] == 'f' && pcbuf[1] == 'd' && pcbuf[2] == 'e' && !radio.RegOpMode.bits.LongRangeMode) {
            if (pcbuf[4] >= '0' && pcbuf[4] <= '9') {
                sscanf(pcbuf+4, "%d", &i);
                fsk.set_tx_fdev_hz(i);
            }
            printf("fdev:%dHz\r\n", fsk.get_tx_fdev_hz());
        } else if (pcbuf[0] == 'f' && pcbuf[1] == 'r' && pcbuf[2] == 'f') {
            if (pcbuf[3] >= '0' && pcbuf[3] <= '9') {
                float MHz;
                sscanf(pcbuf+3, "%f", &MHz);
                //printf("MHz:%f\r\n", MHz);
                radio.set_frf_MHz(MHz);
            }
            printf("%fMHz\r\n", radio.get_frf_MHz());
        } else if (pcbuf[0] == 'p' && pcbuf[1] == 'r' && pcbuf[2] == 'e') {
            if (radio.RegOpMode.bits.LongRangeMode) {
                if (pcbuf[3] >= '0' && pcbuf[3] <= '9') {
                    sscanf(pcbuf+3, "%d", &i);
                    radio.write_u16(REG_LR_PREAMBLEMSB, i);
                }
                lora.RegPreamble = radio.read_u16(REG_LR_PREAMBLEMSB);
                printf("lora PreambleLength:%d\r\n", lora.RegPreamble);                
            } else {
                if (pcbuf[3] >= '0' && pcbuf[3] <= '9') {
                    sscanf(pcbuf+3, "%d", &i);
                    radio.write_u16(REG_FSK_PREAMBLEMSB, i);
                }
                printf("FSK TX PreambleSize:%d\r\n", radio.read_u16(REG_FSK_PREAMBLEMSB));
            }
        } else if (pcbuf[0] == 'p' && pcbuf[1] == 't' && !radio.RegOpMode.bits.LongRangeMode) {
            if (pcbuf[2] >= '0' && pcbuf[2] <= '9') {
                sscanf(pcbuf+2, "%d", &i);
                fsk.RegPreambleDetect.bits.PreambleDetectorTol = i;
                radio.write_reg(REG_FSK_PREAMBLEDETECT, fsk.RegPreambleDetect.octet);
            }
            fsk.RegPreambleDetect.octet = radio.read_reg(REG_FSK_PREAMBLEDETECT);
            printf("PreambleDetectorTol:%d\r\n", fsk.RegPreambleDetect.bits.PreambleDetectorTol);
        } else if (pcbuf[0] == 'p' && pcbuf[1] == 'd' && !radio.RegOpMode.bits.LongRangeMode) {
            fsk.RegPreambleDetect.bits.PreambleDetectorOn ^= 1;
            radio.write_reg(REG_FSK_PREAMBLEDETECT, fsk.RegPreambleDetect.octet);
            printf("PreambleDetector:");
            if (fsk.RegPreambleDetect.bits.PreambleDetectorOn)
                printf("On\r\n");
            else
                printf("OFF\r\n");            
        } else if (pcbuf[0] == 'p' && pcbuf[1] == 'l' && radio.RegOpMode.bits.LongRangeMode) {
            if (pcbuf[2] >= '0' && pcbuf[2] <= '9') {
                sscanf(pcbuf+2, "%d", &i);
                lora.RegPayloadLength = i;
                radio.write_reg(REG_LR_PAYLOADLENGTH, lora.RegPayloadLength);             
            }
            lora.RegPayloadLength = radio.read_reg(REG_LR_PAYLOADLENGTH);
            printf("PayloadLength:%d\r\n", lora.RegPayloadLength);
        } else if (pcbuf[0] == 'd' && pcbuf[1] >= '0' && pcbuf[1] <= '5') {
            switch (pcbuf[1]) {
                case '0':
                    radio.RegDioMapping1.bits.Dio0Mapping++;
                    radio.write_reg(REG_DIOMAPPING1, radio.RegDioMapping1.octet);
                    break;
                case '1':
                    radio.RegDioMapping1.bits.Dio1Mapping++;
                    radio.write_reg(REG_DIOMAPPING1, radio.RegDioMapping1.octet);
                    break;    
                case '2':
                    radio.RegDioMapping1.bits.Dio2Mapping++;
                    radio.write_reg(REG_DIOMAPPING1, radio.RegDioMapping1.octet);
                    break;
                case '3':
                    radio.RegDioMapping1.bits.Dio3Mapping++;
                    radio.write_reg(REG_DIOMAPPING1, radio.RegDioMapping1.octet);
                    break;
                case '4':
                    radio.RegDioMapping2.bits.Dio4Mapping++;
                    radio.write_reg(REG_DIOMAPPING1, radio.RegDioMapping2.octet);
                    break; 
                case '5':
                    radio.RegDioMapping2.bits.Dio5Mapping++;
                    radio.write_reg(REG_DIOMAPPING1, radio.RegDioMapping2.octet);
                    break;                                                                                             
            } // ...switch (pcbuf[1])
            if (radio.RegOpMode.bits.LongRangeMode)
                lora_print_dio();
            else
                fsk_print_dio();
        } else if (pcbuf[0] == 's' && pcbuf[1] == 't' && pcbuf[2] == 'b') {
            radio.set_opmode(RF_OPMODE_STANDBY);
        } else if (pcbuf[0] == 's' && pcbuf[1] == 'l' && pcbuf[2] == 'e') {
            radio.set_opmode(RF_OPMODE_SLEEP);
        } else if (pcbuf[0] == 'c' && pcbuf[1] == 'h' && pcbuf[2] == 'a') {
            app = APP_CHAT;
            lora.start_rx();
            printf("chat start\r\n");
        }           
    }
    printf("> ");
    fflush(stdout);
        
}

int main()
{  

    pc.baud(57600);
    
    radio.frfs = frfs;

    while(1) {
        switch (app) {
            case APP_NONE:
                console();
                break;
            case APP_CHAT:
                console_chat();
                break;
        } // ...switch (app)
    } // ...while(1)
}

/*
GPS, Pressure sensor, touch sensor etc
3-axis accelerometer: MMA8415IQ      peripherials/mma8415..c
SX9500 SAR,   peripherials/sx9500.c
altimeter & temperature: MPL3115A2.   peripherials/mpl3115.c
GPS: NMEA from system/gps.c, boards/LoRaMote/gps-board.c
 * 
*/