Lab_interaccio/2012/ASK-Shield/References/waspmote-api-v.021/WaspPWR.cpp
Miguel Angel de Heras 451795bb92 Second commit
2025-03-05 15:57:19 +01:00

498 lines
12 KiB
C++

/*
* Copyright (C) 2009 Libelium Comunicaciones Distribuidas S.L.
* http://www.libelium.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Version: 1.1
* Design: David Gascón
* Implementation: Alberto Bielsa, David Cuartielles
*/
#ifndef __WPROGRAM_H__
#include "WaspClasses.h"
#endif
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
// Variables ////////////////////////////////////////////////////////////////
// these two variables have been moved to the general system
uint8_t intIPRA = 0;
uint8_t intIPRB = 0;
// Constructors ////////////////////////////////////////////////////////////////
WaspPWR::WaspPWR()
{
// nothing to do when constructing
}
// Private Methods /////////////////////////////////////////////////////////////
/* setIPF ( peripheral )
* - sets a certain internal peripheral on
* - to control the pwr on the different internal peripherals it is
* convenient to read MCU's manual on pgs. 56/57
* FIXME: missing all the Timers and UART to reduce consumption
*/
void WaspPWR::setIPF(uint8_t peripheral)
{
setIPF_(peripheral);
intIPRA = IPRA;
}
/* resetIPR ( peripheral )
* - resets a certain internal peripheral to off
* - to control the pwr on the different internal peripherals it is
* convenient to read MCU's manual on pgs. 56/57
* FIXME: missing all the Timers and UART to reduce consumption
*/
void WaspPWR::resetIPF(uint8_t peripheral)
{
resetIPF_(peripheral);
intIPRA = IPRA;
}
/* uint8_t getIPR ( )
* - answers with the whole IPR
*/
uint8_t WaspPWR::getIPF()
{
return intIPRA;
}
// Public Methods //////////////////////////////////////////////////////////////
/* setSensorPower( type, mode) - set ON/OFF 3V3 or 5V switches
*
* It sets ON/OFF 3V3 or 5V switches
*/
void WaspPWR::setSensorPower(uint8_t type, uint8_t mode)
{
pinMode(SENS_PW_3V3,OUTPUT);
pinMode(SENS_PW_5V,OUTPUT);
switch( type )
{
case SENS_3V3: if(mode==SENS_ON) digitalWrite(SENS_PW_3V3,HIGH);
else if(mode==SENS_OFF) digitalWrite(SENS_PW_3V3,LOW);
break;
case SENS_5V: if(mode==SENS_ON) digitalWrite(SENS_PW_5V,HIGH);
else if(mode==SENS_OFF) digitalWrite(SENS_PW_5V,LOW);
break;
}
}
/* setWatchdog( mode, timer) - enables or disables watchdog interruption
*
* It enables or disables watchdog interruption.
*
* 'mode' --> if mode=WTD_ON, it enables watchdog interruption. If mode=WTD_OFF, it disables watchdog interruption.
* 'timer' --> it specifies the time before the watchdog activates the interruption. Possible values are:
* WTD_16MS 0
* WTD_32MS 1
* WTD_64MS 2
* WTD_128MS 3
* WTD_250MS 4
* WTD_500MS 5
* WTD_1S 6
* WTD_2S 7
* WTD_4S 8
* WTD_8S 9
*
* It returns nothing
*/
void WaspPWR::setWatchdog(uint8_t mode, uint8_t timer)
{
if(mode==WTD_ON)
{
enableInterrupts(WTD_INT);
setup_watchdog(timer); // set watchdog interrupt to wake up from Sleep Power Down Mode
}
if(mode==WTD_OFF)
{
disableInterrupts(WTD_INT);
off_watchdog();
}
}
/* switchesOFF() - switches off the Waspmote switches specified
*
* It switches off all Waspmote switches
*/
void WaspPWR::switchesOFF(uint8_t option)
{
cbi(ADCSRA,ADEN); // switch Analog to Digital Converter OFF
pinMode(SERID_PW,OUTPUT);
digitalWrite(SERID_PW,LOW);
pinMode(MEM_PW,OUTPUT);
digitalWrite(MEM_PW,LOW);
if( option & SENS_OFF )
{
pinMode(SENS_PW_3V3,OUTPUT);
digitalWrite(SENS_PW_3V3,LOW);
pinMode(SENS_PW_5V,OUTPUT);
digitalWrite(SENS_PW_5V,LOW);
}
if( option & UART0_OFF )
{
XBee.setMode(XBEE_OFF);
}
if( option & UART1_OFF )
{
closeSerial(1);
pinMode(MUX_PW, OUTPUT);
digitalWrite(MUX_PW, LOW);
pinMode(GPS_PW, OUTPUT);
digitalWrite(GPS_PW, LOW);
}
if( option & RTC_OFF )
{
if( !(ACC.AccEventMode & ACC_FREE_FALL) && !(ACC.AccEventMode & ACC_DIRECTION) )
{
pinMode(RTC_PW,OUTPUT);
digitalWrite(RTC_PW,LOW);
}
}
if( option & BAT_OFF )
{
pinMode(BAT_MONITOR_PW,OUTPUT);
digitalWrite(BAT_MONITOR_PW,LOW);
}
}
/* switchesON() - switches on all Waspmote switches
*
* It switches on all Waspmote switches
*/
void WaspPWR::switchesON(uint8_t option)
{
sbi(ADCSRA,ADEN); // switch Analog to Digital Converter ON
}
/* clearInts() - clears all captured interrupts to allow new interrupts on that modules
*
* It clears all captured interrupts to allow new interrupts on that modules
*/
void WaspPWR::clearInts()
{
if( intFlag & ACC_INT )
{
ACC.setFF();
}
if( intFlag & BAT_INT )
{
}
if( intFlag & RTC_INT ) // hay que mirar si está inicializado el I2C
{
RTC.clearAlarmFlag();
}
if( intFlag & UART1_INT )
{
enableInterrupts(UART1_INT);
}
if( intFlag & WTD_INT )
{
}
if( intFlag & SENS_INT )
{
}
}
/* sleep() - sets the microcontroller to the lowest consumption sleep mode
*
* It sets the microcontroller to the lowest consumption sleep mode. Before setting this state, some interruption
* should be enabled to be able to wake up the microcontroller from this state.
*
* It switches off all the switches on the Waspmote board.
*
* It returns nothing.
*/
void WaspPWR::sleep(uint8_t option)
{
switchesOFF(option);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode();
sleep_disable();
switchesON(option);
}
/* sleep(timer) - sets the microcontroller to the lowest consumption sleep mode
*
* It sets the microcontroller to the lowest consumption sleep mode. It enables watchdog interruption to be able to
* wake up the microcontroller after 'timer' time.
*
* 'timer' --> it specifies the time before the watchdog activates the interruption. Possible values are:
* WTD_16MS 0
* WTD_32MS 1
* WTD_64MS 2
* WTD_128MS 3
* WTD_250MS 4
* WTD_500MS 5
* WTD_1S 6
* WTD_2S 7
* WTD_4S 8
* WTD_8S 9
*
* It switches off all the switches on the Waspmote board.
*
* It returns nothing.
*/
void WaspPWR::sleep(uint8_t timer, uint8_t option)
{
switchesOFF(option);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
setWatchdog(WTD_ON,timer);
sleep_mode();
sleep_disable();
switchesON(option);
}
/* deepSleep(time2wake, offset, mode) - sets the microcontroller to the lowest consumption sleep mode
*
* It sets the microcontroller to the lowest consumption sleep mode. It enables RTC interruption to be able to
* wake up the microcontroller when the RTC alarm is launched.
*
* 'time2wake' --> it specifies the time at which the RTC alarm will activate. It must follow the next format:
* "DD:HH:MM:SS"
* 'offset' --> it specifies if 'time2wake' is added to the actual time or if this time is set as the alarm
* 'mode' --> it specifies the mode for RTC alarm
*
* It uses Alarm1 on the RTC due to this Alarm has more precision than Alarm2
*
* It switches off all the switches on the Waspmote board.
*
* It returns nothing.
*/
void WaspPWR::deepSleep(const char* time2wake, uint8_t offset, uint8_t mode, uint8_t option)
{
// Set RTC alarme to wake up from Sleep Power Down Mode
RTC.setAlarm1(time2wake,offset,mode);
RTC.close();
switchesOFF(option);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode();
sleep_disable();
switchesON(option);
RTC.ON();
RTC.clearAlarmFlag();
if( option & RTC_OFF ) RTC.OFF();
}
/* hibernate(time2wake, offset, mode) - switches off the general switch and enables RTC interruption
*
* It switches off the general switch and enables RTC interruption. It enables RTC interruption to be able to
* switch on the general switch.
*
* When this function is called, Waspmote has no power and when RTC alarm is activated, the power will return to
* the board. This will cause the Waspmote inits again, restarting the code from the init.
*
* 'time2wake' --> it specifies the time at which the RTC alarm will activate. It must follow the next format:
* "DD:HH:MM:SS"
* 'offset' --> it specifies if 'time2wake' is added to the actual time or if this time is set as the alarm
* 'mode' --> it specifies the mode for RTC alarm
*
* It uses Alarm1 on the RTC due to this Alarm has more precision than Alarm2
*
* It switches off all the switches on the Waspmote board.
*
* It returns nothing.
*/
void WaspPWR::hibernate(const char* time2wake, uint8_t offset, uint8_t mode)
{
pinMode(XBEE_PW,OUTPUT);
digitalWrite(XBEE_PW, LOW);
closeSerial(0);
while(digitalRead(GPS_PW))
{
digitalWrite(GPS_PW,LOW);
}
RTC.ON();
// Set RTC alarme to wake up from Sleep Power Down Mode
RTC.setAlarm1(time2wake,offset,mode);
RTC.close();
RTC.setMode(RTC_OFF, RTC_NORMAL_MODE);
Utils.writeEEPROM(HIB_ADDR,HIB_VALUE);
pinMode(RTC_SLEEP,OUTPUT);
digitalWrite(RTC_SLEEP,HIGH);
delay(18);
digitalWrite(RTC_SLEEP,LOW);
// To avoid executing any other function after calling hibernate
while(1);
}
/* getBatteryLevel() - gets % of remaining battery
*
* It gets the % of remaining battery.
*
* It gives a value of 1024 for +3V3
* A resistor bridge is put to down max +4V2 battery level around +2V07 on 100% battery charge
* Minimum value for good battery is +1V5, so with resistor bridge is set to +0V75
* Values (in this case) are from 204 to 567
*/
uint8_t WaspPWR::getBatteryLevel()
{
float aux=0;
uint8_t resul=0;
pinMode(BAT_MONITOR_PW,OUTPUT);
digitalWrite(BAT_MONITOR_PW,HIGH);
aux=analogRead(0);
if (aux < 512)
{
aux = 0;
resul=(uint8_t) aux;
digitalWrite(BAT_MONITOR_PW,LOW);
return resul;
}
if (aux > 651)
{
aux = 100;
resul=(uint8_t) aux;
digitalWrite(BAT_MONITOR_PW,LOW);
return resul;
}
if ((aux <= 651)&&(aux > 543))
{ aux = (aux * (90.0/108.0)) - 442.0;
resul=(uint8_t) aux;
digitalWrite(BAT_MONITOR_PW,LOW);
return resul;
}
else
{
aux = ((10.0/(543.0-511.0)) * aux) - 160.0;
resul=(uint8_t) aux;
digitalWrite(BAT_MONITOR_PW,LOW);
return resul;
}
}
/* getBatteryVolts() - gets Volts of remaining battery
*
* This function gets the Volts of remaining battery.
*
* Returns the voltage of battery.
*/
float WaspPWR::getBatteryVolts()
{
float aux_volts=0;
pinMode(BAT_MONITOR_PW,OUTPUT);
digitalWrite(BAT_MONITOR_PW,HIGH);
aux_volts=analogRead(0);
digitalWrite(BAT_MONITOR_PW,LOW);
return aux_volts*3.3*2.0/1023.0;
}
/* closeI2C() - closes I2C, setting SDA and SCL to '0'
*
* This function closes I2C, setting SDA and SCL to '0'
*
* Returns nothing
*/
void WaspPWR::closeI2C()
{
pinMode(I2C_SDA,OUTPUT);
pinMode(I2C_SCL,OUTPUT);
Wire.close();
}
// inits the value of the digipot used in the battery detector
void WaspPWR::setLowBatteryThreshold(float threshold)
{
uint8_t dig=0;
uint8_t rpot=200;
dig = uint8_t (rpot-(((threshold-1.15)*470/1.15)-806))*255/rpot;
if( !Wire.I2C_ON ) Wire.begin();
delay(200);
Wire.beginTransmission(0x2d); // Address
Wire.send(0x11); // Write command
Wire.send(dig); // Data
Wire.endTransmission();
if( Wire.I2C_ON ) closeI2C();
}
// checks if Hibernate has generated the reset
void WaspPWR::ifHibernate()
{
if( digitalRead(RTC_INT_PIN_MON) && (Utils.readEEPROM(HIB_ADDR)==HIB_VALUE) )
{
intFlag |= HIB_INT;
}
Utils.writeEEPROM(HIB_ADDR,0);
if( !(intFlag & HIB_INT) )
{
pinMode(RST_RTC, OUTPUT);
digitalWrite(RST_RTC, LOW);
delay(10);
digitalWrite(RST_RTC, HIGH);
}
if( !(intFlag & HIB_INT) )
{
Utils.setLED(LED0,LED_ON);
delay(1000);
Utils.setLED(LED0,LED_OFF);
}
}
// reboots waspmote
void WaspPWR::reboot()
{
__asm__("jmp 0x1E000");
}
// Private Methods /////////////////////////////////////////////////////////////
// Preinstantiate Objects //////////////////////////////////////////////////////
WaspPWR PWR = WaspPWR();