p2p-pingpong-clickbutton

Dependencies:   PingPong-P2P-ClickButtonToWork-SX1272 Lora_SX1272_Coragem

main.cpp

Committer:
cdupaty
Date:
2017-11-05
Revision:
0:9859cc8476f2
Child:
1:9f961d34dd8d

File content as of revision 0:9859cc8476f2:

/*
 *  temperature sensor on analog 8 to test the LoRa gateway
 *
 *  Copyright (C) 2016 Congduc Pham, University of Pau, France
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.

 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with the program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *****************************************************************************
 * last update: Sep. 29th, 2017 by C. Pham
 * last update: oct 30th , 2017 by C.Dupaty
 */
#include "mbed.h"

#include <SPI.h> 
// Include the SX1272
#include "SX1272.h"

// IMPORTANT
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// please uncomment only 1 choice
//
#define ETSI_EUROPE_REGULATION
//#define FCC_US_REGULATION
//#define SENEGAL_REGULATION
/////////////////////////////////////////////////////////////////////////////////////////////////////////// 

// IMPORTANT
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// please uncomment only 1 choice
#define BAND868
//#define BAND900
//#define BAND433
///////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifdef ETSI_EUROPE_REGULATION
#define MAX_DBM 14
// previous way for setting output power
// char powerLevel='M';
#elif defined SENEGAL_REGULATION
#define MAX_DBM 10
// previous way for setting output power
// 'H' is actually 6dBm, so better to use the new way to set output power
// char powerLevel='H';
#elif defined FCC_US_REGULATION
#define MAX_DBM 14
#endif

#ifdef BAND868
#ifdef SENEGAL_REGULATION
const uint32_t DEFAULT_CHANNEL=CH_04_868;
#else
const uint32_t DEFAULT_CHANNEL=CH_10_868;
#endif
#elif defined BAND900
const uint32_t DEFAULT_CHANNEL=CH_05_900;
#elif defined BAND433
const uint32_t DEFAULT_CHANNEL=CH_00_433;
#endif

// IMPORTANT
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// uncomment if your radio is an HopeRF RFM92W, HopeRF RFM95W, Modtronix inAir9B, NiceRF1276
// or you known from the circuit diagram that output use the PABOOST line instead of the RFO line
//#define PABOOST
/////////////////////////////////////////////////////////////////////////////////////////////////////////// 

///////////////////////////////////////////////////////////////////
// COMMENT OR UNCOMMENT TO CHANGE FEATURES. 
// ONLY IF YOU KNOW WHAT YOU ARE DOING!!! OTHERWISE LEAVE AS IT IS
//#define WITH_EEPROM             //  tous uncomment a l origine sauf WITH_ACK
#define WITH_APPKEY
#define FLOAT_TEMP
#define NEW_DATA_FIELD
//#define LOW_POWER
//#define LOW_POWER_HIBERNATE
//#define WITH_ACK
///////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////
// ADD HERE OTHER PLATFORMS THAT DO NOT SUPPORT EEPROM NOR LOW POWER
#if defined ARDUINO_SAM_DUE || defined __SAMD21G18A__ || defined TARGET_NUCLEO_L073RZ
#undef WITH_EEPROM
#endif

#if defined ARDUINO_SAM_DUE || defined TARGET_NUCLEO_L073RZ
#undef LOW_POWER
#endif
///////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////
// CHANGE HERE THE LORA MODE, NODE ADDRESS 
#define LORAMODE  1
#define node_addr 6
//////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////
// CHANGE HERE THE THINGSPEAK FIELD BETWEEN 1 AND 4
#define field_index 1
///////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////
// CHANGE HERE THE READ PIN AND THE POWER PIN FOR THE TEMP. SENSOR
#define TEMP_PIN_READ  PA_0
// use digital 9 to power the temperature sensor if needed
#define TEMP_PIN_POWER PA_1
///////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////
// CHANGE HERE THE TIME IN MINUTES BETWEEN 2 READING & TRANSMISSION
unsigned int idlePeriodInMin = 2;
///////////////////////////////////////////////////////////////////

#ifdef WITH_APPKEY
///////////////////////////////////////////////////////////////////
// CHANGE HERE THE APPKEY, BUT IF GW CHECKS FOR APPKEY, MUST BE
// IN THE APPKEY LIST MAINTAINED BY GW.
uint8_t my_appKey[4]={5, 6, 7, 8};
///////////////////////////////////////////////////////////////////
#endif

// we wrapped Serial.println to support the Arduino Zero or M0
#if defined __SAMD21G18A__ && not defined ARDUINO_SAMD_FEATHER_M0
#define PRINTLN                   SerialUSB.println("")              
#define PRINT_CSTSTR(fmt,param)   SerialUSB.print(F(param))
#define PRINT_STR(fmt,param)      SerialUSB.print(param)
#define PRINT_VALUE(fmt,param)    SerialUSB.print(param)
#define FLUSHOUTPUT               SerialUSB.flush();
#else
#define PRINTLN                   Serial.println("")
#define PRINT_CSTSTR(fmt,param)   Serial.print(F(param))
#define PRINT_STR(fmt,param)      Serial.print(param)
#define PRINT_VALUE(fmt,param)    Serial.print(param)
#define FLUSHOUTPUT               Serial.flush();
#endif

#ifdef WITH_EEPROM
#include <EEPROM.h>
#endif

#define DEFAULT_DEST_ADDR 1

#ifdef WITH_ACK
#define NB_RETRIES 2
#endif

#if defined ARDUINO_AVR_PRO || defined ARDUINO_AVR_MINI || defined ARDUINO_SAM_DUE || defined __MK20DX256__  || defined __MKL26Z64__ || defined __MK64FX512__ || defined __MK66FX1M0__ || defined __SAMD21G18A__
  // if you have a Pro Mini running at 5V, then change here
  // these boards work in 3.3V
  // Nexus board from Ideetron is a Mini
  // __MK66FX1M0__ is for Teensy36
  // __MK64FX512__  is for Teensy35
  // __MK20DX256__ is for Teensy31/32
  // __MKL26Z64__ is for TeensyLC
  // __SAMD21G18A__ is for Zero/M0 and FeatherM0 (Cortex-M0)
  #define TEMP_SCALE  3300.0
#else // ARDUINO_AVR_NANO || defined ARDUINO_AVR_UNO || defined ARDUINO_AVR_MEGA2560 
  // also for all other boards, so change here if required.
  #define TEMP_SCALE  5000.0
#endif

#ifdef LOW_POWER
// this is for the Teensy36, Teensy35, Teensy31/32 & TeensyLC
// need v6 of Snooze library
#if defined __MK20DX256__ || defined __MKL26Z64__ || defined __MK64FX512__ || defined __MK66FX1M0__
#define LOW_POWER_PERIOD 60
#include <Snooze.h>
SnoozeTimer timer;
SnoozeBlock sleep_config(timer);
//#elif defined ARDUINO_AVR_FEATHER32U4
//#define LOW_POWER_PERIOD 8
//#include "Adafruit_SleepyDog.h"
#else // for all other boards based on ATMega168, ATMega328P, ATMega32U4, ATMega2560, ATMega256RFR2, ATSAMD21G18A
#define LOW_POWER_PERIOD 8
// you need the LowPower library from RocketScream
// https://github.com/rocketscream/Low-Power
#include "LowPower.h"

#ifdef __SAMD21G18A__
// use the RTC library
#include "RTCZero.h"
/* Create an rtc object */
RTCZero rtc;
#endif
#endif
unsigned int nCycle = idlePeriodInMin*60/LOW_POWER_PERIOD;
#endif

double temp;
unsigned long nextTransmissionTime=0L;
char float_str[20];
uint8_t message[100];
int loraMode=LORAMODE;

#ifdef WITH_EEPROM
struct sx1272config {

  uint8_t flag1;
  uint8_t flag2;
  uint8_t seq;
  // can add other fields such as LoRa mode,...
};

sx1272config my_sx1272config;
#endif

// ajoute par C.Dupaty
//Serial pcmain(USBTX, USBRX); // tx, rx
DigitalOut temp_pin_power(TEMP_PIN_POWER);
AnalogIn temp_pin_read(TEMP_PIN_READ);

void setup()
{
  int e;

  // for the temperature sensor
  //pinMode(TEMP_PIN_READ, INPUT);
  // and to power the temperature sensor
  //pinMode(TEMP_PIN_POWER,OUTPUT);

#ifdef LOW_POWER
#ifdef __SAMD21G18A__
  rtc.begin();
#endif  
#else
 // digitalWrite(TEMP_PIN_POWER,HIGH);
 temp_pin_power=1;
#endif

  wait_ms(3000);
/*
  // Open serial communications and wait for port to open:
#if defined __SAMD21G18A__ && not defined ARDUINO_SAMD_FEATHER_M0 
  SerialUSB.begin(38400);
#else
 Serial.begin(38400);  
#endif 
*/
 
  // Print a start message
  printf("%s","Simple LoRa temperature sensor\n");
  printf("%s","--------------------------------\n");
  printf("%s","---- VERSION NUCLEO STM32-------\n");
  printf("%s","--------------------------------\n");
#ifdef ARDUINO_AVR_PRO
  printf("%s","Arduino Pro Mini detected\n");  
#endif
#ifdef ARDUINO_AVR_NANO
  printf("%s","Arduino Nano detected\n");   
#endif
#ifdef ARDUINO_AVR_MINI
  printf("%s","Arduino Mini/Nexus detected\n");  
#endif
#ifdef ARDUINO_AVR_MEGA2560
  printf("%s","Arduino Mega2560 detected\n");  
#endif
#ifdef ARDUINO_SAM_DUE
  printf("%s","Arduino Due detected\n");  
#endif
#ifdef __MK66FX1M0__
  printf("%s","Teensy36 MK66FX1M0 detected\n");
#endif
#ifdef __MK64FX512__
  printf("%s","Teensy35 MK64FX512 detected\n");
#endif
#ifdef __MK20DX256__
  printf("%s","Teensy31/32 MK20DX256 detected\n");
#endif
#ifdef __MKL26Z64__
  printf("%s","TeensyLC MKL26Z64 detected\n");
#endif
#ifdef ARDUINO_SAMD_ZERO 
  printf("%s","Arduino M0/Zero detected\n");
#endif
#ifdef ARDUINO_AVR_FEATHER32U4 
  printf("%s","Adafruit Feather32U4 detected\n"); 
#endif
#ifdef ARDUINO_SAMD_FEATHER_M0
  printf("%s","Adafruit FeatherM0 detected\n");
#endif

// See http://www.nongnu.org/avr-libc/user-manual/using_tools.html
// for the list of define from the AVR compiler

#ifdef __AVR_ATmega328P__
  printf("%s","ATmega328P detected\n");
#endif 
#ifdef __AVR_ATmega32U4__
  printf("%s","ATmega32U4 detected\n");
#endif 
#ifdef __AVR_ATmega2560__
  printf("%s","ATmega2560 detected\n");
#endif 
#ifdef __SAMD21G18A__ 
  printf("%s","SAMD21G18A ARM Cortex-M0 detected\n");
#endif
#ifdef __SAM3X8E__ 
  printf("%s","SAM3X8E ARM Cortex-M3 detected\n");
#endif

#ifdef TARGET_NUCLEO_L073RZ
  printf("%s","NUCLEO L073RZ detected\n");
#endif

  // Power ON the module
  sx1272.ON();

#ifdef WITH_EEPROM
  // get config from EEPROM
  EEPROM.get(0, my_sx1272config);

  // found a valid config?
  if (my_sx1272config.flag1==0x12 && my_sx1272config.flag2==0x34) {
    printf("%s","Get back previous sx1272 config\n");

    // set sequence number for SX1272 library
    sx1272._packetNumber=my_sx1272config.seq;
    printf("%s","Using packet sequence number of ");
    printf("%d", sx1272._packetNumber);
    printf("\n");
  }
  else {
    // otherwise, write config and start over
    my_sx1272config.flag1=0x12;
    my_sx1272config.flag2=0x34;
    my_sx1272config.seq=sx1272._packetNumber;
  }
#endif
  
  int error_config_sx1272=0;
  
  // Set transmission mode and print the result
  printf("%s","\n-------------------------DEBUT Setting mode -----------> \n");
  e = sx1272.setMode(loraMode);
  printf("%s","\n-------------------------FIN Setting mode -----------> \n");
  if (e) error_config_sx1272=1;
  printf("%s","Setting Mode: state ");
  printf("%d", e);
  printf("\n");

  // enable carrier sense
  sx1272._enableCarrierSense=true;
#ifdef LOW_POWER
  // TODO: with low power, when setting the radio module in sleep mode
  // there seem to be some issue with RSSI reading
  sx1272._RSSIonSend=false;
#endif   
    
  // Select frequency channel
  e = sx1272.setChannel(DEFAULT_CHANNEL);
  if (e) error_config_sx1272=1;
  printf("%s","Setting Channel: state ");
  printf("%d", e);
  printf("\n");
  
  // Select amplifier line; PABOOST or RFO
#ifdef PABOOST
  sx1272._needPABOOST=true;
  // previous way for setting output power
  // powerLevel='x';
#else
  // previous way for setting output power
  // powerLevel='M';  
#endif

  // previous way for setting output power
  // e = sx1272.setPower(powerLevel); 

  e = sx1272.setPowerDBM((uint8_t)MAX_DBM);
  if (e) error_config_sx1272=1;
  printf("%s","Setting Power: state ");
  printf("%d", e);
  printf("\n");
  
  // Set the node address and print the result
  e = sx1272.setNodeAddress(node_addr);
  if (e) error_config_sx1272=1;
  printf("%s","Setting node addr: state ");
  printf("%d", e);
  printf("\n");
  
  // Print a success message
  if (!error_config_sx1272) printf("%s","SX1272 successfully configured\n");
  else printf("%s","ERREUR DE CONFIGURATION DU SX1272\n");

  wait_ms(500);
}

char *ftoa(char *a, double f, int precision)
{
 long p[] = {0,10,100,1000,10000,100000,1000000,10000000,100000000};
 
 char *ret = a;
 long heiltal = (long)f;
 //modifie pa C.Dupaty
// itoa(heiltal, a, 10);
sprintf(a,"%d",heiltal);
 while (*a != '\0') a++;
 *a++ = '.';
 long desimal = abs((long)((f - heiltal) * p[precision]));
 if (desimal < p[precision-1]) {
  *a++ = '0';
 } 
 
  //modifie pa C.Dupaty
//  itoa(desimal, a, 10);
sprintf(a,"%d",desimal);


 return ret;
}


//////////////////////////////////////////////////////////////
//  programme principal , loop sur Arduino
//////////////////////////////////////////////////////////////
int main(void)
{
  long startSend;
  long endSend;
  uint8_t app_key_offset=0;
  int e;
  
  setup();
  
while(1)  { /////////////// debut boucle
//printf("%s","\n-------------------------BOUCLE SANS FIN -----------> \n");
//while(1); 

#ifndef LOW_POWER
  // 600000+random(15,60)*1000
  if (millis() > nextTransmissionTime) {
#endif

#ifdef LOW_POWER
    //  digitalWrite(TEMP_PIN_POWER,HIGH);
    temp_pin_power=1;
      // security?
      wait_ms(200);   
#endif

      temp = 0;
      int value;
      
      for (int i=0; i<10; i++) {
          // change here how the temperature should be computed depending on your sensor type
          // 
           value = temp_pin_read;
          temp += (value*TEMP_SCALE/1024.0)/10;
        
          printf("%s","Reading ");
          printf("%d", value);
          printf("\n");   
          wait_ms(100);
      }
      
#ifdef LOW_POWER
      //digitalWrite(TEMP_PIN_POWER,LOW);
      temp_pin_ower=0;
#endif

      printf("%s","Mean temp is ");
      temp = temp/10;
      printf("%f", temp);
      printf("\n");
      
#ifdef WITH_APPKEY
      app_key_offset = sizeof(my_appKey);
      // set the app key in the payload
      memcpy(message,my_appKey,app_key_offset);
#endif

      uint8_t r_size;
      
#ifdef FLOAT_TEMP
      ftoa(float_str,temp,2);

#ifdef NEW_DATA_FIELD
      // this is for testing, uncomment if you just want to test, without a real temp sensor plugged
      //strcpy(float_str, "21.55567");
      r_size=sprintf((char*)message+app_key_offset,"\\!#%d#TC/%s",field_index,float_str);
#else
      // this is for testing, uncomment if you just want to test, without a real temp sensor plugged
      //strcpy(float_str, "21.55567");
      r_size=sprintf((char*)message+app_key_offset,"\\!#%d#%s",field_index,float_str);
#endif
      
#else
      
#ifdef NEW_DATA_FIELD      
      r_size=sprintf((char*)message+app_key_offset, "\\!#%d#TC/%d", field_index, (int)temp);   
#else
      r_size=sprintf((char*)message+app_key_offset, "\\!#%d#%d", field_index, (int)temp);
#endif         
#endif

      printf("%s","Sending ");
      printf("%s",(char*)(message+app_key_offset));
      printf("\n");
      
      printf("%s","Real payload size is ");
      printf("%d", r_size);
      printf("\n");
      
      int pl=r_size+app_key_offset;
      
      sx1272.CarrierSense();
      
      startSend=millis();

#ifdef WITH_APPKEY
      // indicate that we have an appkey
      sx1272.setPacketType(PKT_TYPE_DATA | PKT_FLAG_DATA_WAPPKEY);
#else
      // just a simple data packet
      sx1272.setPacketType(PKT_TYPE_DATA);
#endif
      
      // Send message to the gateway and print the result
      // with the app key if this feature is enabled
#ifdef WITH_ACK
      int n_retry=NB_RETRIES;
      
      do {
        e = sx1272.sendPacketTimeoutACK(DEFAULT_DEST_ADDR, message, pl);

        if (e==3)
          printf("%s","No ACK");
        
        n_retry--;
        
        if (n_retry)
          printf("%s","Retry");
        else
          printf("%s","Abort"); 
          
      } while (e && n_retry);          
#else      
      e = sx1272.sendPacketTimeout(DEFAULT_DEST_ADDR, message, pl);
#endif  
      endSend=millis();
    
#ifdef WITH_EEPROM
      // save packet number for next packet in case of reboot
      my_sx1272config.seq=sx1272._packetNumber;
      EEPROM.put(0, my_sx1272config);
#endif

      printf("%s","LoRa pkt size ");
      printf("%d", pl);
      printf("\n");
      
      printf("%s","LoRa pkt seq ");
      printf("%d", sx1272.packet_sent.packnum);
      printf("\n");
    
      printf("%s","LoRa Sent in ");
      printf("%ld", endSend-startSend);
      printf("\n");
          
      printf("%s","LoRa Sent w/CAD in ");
      printf("%ld", endSend-sx1272._startDoCad);
      printf("\n");

      printf("%s","Packet sent, state ");
      printf("%d", e);
      printf("\n");

      printf("%s","Remaining ToA is ");
      printf("%d", sx1272.getRemainingToA());
      printf("\n");
        
#if defined LOW_POWER && not defined ARDUINO_SAM_DUE
      printf("%s","Switch to power saving mode\n");

      e = sx1272.setSleepMode();

      if (!e)
        printf("%s","Successfully switch LoRa module in sleep mode\n");
      else  
        printf("%s","Could not switch LoRa module in sleep mode\n");
        
      FLUSHOUTPUT
      wait_ms(50);

#ifdef __SAMD21G18A__
      // For Arduino M0 or Zero we use the built-in RTC
      //LowPower.standby();
      rtc.setTime(17, 0, 0);
      rtc.setDate(1, 1, 2000);
      rtc.setAlarmTime(17, idlePeriodInMin, 0);
      // for testing with 20s
      //rtc.setAlarmTime(17, 0, 20);
      rtc.enableAlarm(rtc.MATCH_HHMMSS);
      //rtc.attachInterrupt(alarmMatch);
      rtc.standbyMode();

      printf("%s","SAMD21G18A wakes up from standby\n");      
      FLUSHOUTPUT
#else
      nCycle = idlePeriodInMin*60/LOW_POWER_PERIOD + random(2,4);

#if defined __MK20DX256__ || defined __MKL26Z64__ || defined __MK64FX512__ || defined __MK66FX1M0__
      // warning, setTimer accepts value from 1ms to 65535ms max
      timer.setTimer(LOW_POWER_PERIOD*1000 + random(1,5)*1000);// milliseconds

      nCycle = idlePeriodInMin*60/LOW_POWER_PERIOD;
#endif          
      for (int i=0; i<nCycle; i++) {  

#if defined ARDUINO_AVR_PRO || defined ARDUINO_AVR_NANO || defined ARDUINO_AVR_UNO || defined ARDUINO_AVR_MINI || defined __AVR_ATmega32U4__ 
          // ATmega328P, ATmega168, ATmega32U4
          LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
          
          //LowPower.idle(SLEEP_8S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, 
          //              SPI_OFF, USART0_OFF, TWI_OFF);
#elif defined ARDUINO_AVR_MEGA2560
          // ATmega2560
          LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
          
          //LowPower.idle(SLEEP_8S, ADC_OFF, TIMER5_OFF, TIMER4_OFF, TIMER3_OFF, 
          //      TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, SPI_OFF, USART3_OFF, 
          //      USART2_OFF, USART1_OFF, USART0_OFF, TWI_OFF);
#elif defined __MK20DX256__ || defined __MKL26Z64__ || defined __MK64FX512__ || defined __MK66FX1M0__
          // Teensy31/32 & TeensyLC
#ifdef LOW_POWER_HIBERNATE
          Snooze.hibernate(sleep_config);
#else            
          Snooze.deepSleep(sleep_config);
#endif
#else
          // use the wait_ms function
          wait_ms(LOW_POWER_PERIOD*1000);
#endif                        
          printf("%s",".");
          FLUSHOUTPUT
          wait_ms(10);                        
      }
      
      wait_ms(50);
#endif      
      
#else
      printf("%ld ", nextTransmissionTime);
      printf("%s","Will send next value at ");
      // use a random part also to avoid collision
      nextTransmissionTime=millis()+(unsigned long)idlePeriodInMin*60*1000+(unsigned long)(rand()%60+15)*1000;
      printf("%ld", nextTransmissionTime);
      printf("\n");
  }
#endif

}//  fin boucle

//return (0);

}