Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: TextLCD nRF24L01P mbed
main.cpp
- Committer:
- jackmax
- Date:
- 2017-01-22
- Revision:
- 10:3417715786be
- Parent:
- 9:53da36425601
- Child:
- 11:c94b9db597e9
File content as of revision 10:3417715786be:
#include "mbed.h"
//#include "rtos.h"
#include "TextLCD.h"
#include "custom-chars.h"
#include "melodies.h"
#include "nRF24L01P.h"
#include <string>
#include <vector>
time_t next_alarm = 0;
// Host PC Communication channels
Serial pc(USBTX, USBRX); // tx, rx
I2C i2c_lcd(D5,D7); // SDA, SCL pins. Change if necessary
TextLCD_I2C lcd(&i2c_lcd, 0x4E, TextLCD::LCD16x2); // I2C exp: I2C bus, PCF8574 Slaveaddress, LCD Type
//Light sensor
#define LIGHT_INTERVAL 2
AnalogIn light_sensor(A1);
double light_sum;
int light_samples;
time_t next_light = 0;
//Mutex light_mutex;
void lightSensor(){
light_sum += light_sensor;
light_samples++;
next_light = time(NULL) + LIGHT_INTERVAL;
}
//2.4 GHz radio
#define RX_ADDRESS ((unsigned long long) 0xABCDEF00)
#define TX_ADDRESS ((unsigned long long) 0xABCDEF01)
#define TRANSFER_SIZE 32
nRF24L01P radio(PB_15, PB_14, PB_13, PB_12, PB_1, PB_2);
void initRadio(int channel, int power, int datarate){
radio.powerDown();
radio.powerUp();
radio.setAirDataRate(datarate);
radio.setRfOutputPower(power);
radio.setRfFrequency(NRF24L01P_MIN_RF_FREQUENCY + 4 * channel);
radio.setCrcWidth(NRF24L01P_CRC_8_BIT);
radio.enableAutoAcknowledge(NRF24L01P_PIPE_P0);
radio.enableAutoAcknowledge(NRF24L01P_PIPE_P1);
radio.enableAutoRetransmit(0x0F, 0x0F);
radio.setTxAddress(TX_ADDRESS, 4);
radio.setRxAddress(TX_ADDRESS, 4, NRF24L01P_PIPE_P0);
radio.setRxAddress(RX_ADDRESS, 4, NRF24L01P_PIPE_P1);
// Display the (default) setup of the nRF24L01+ chip
pc.printf( "nRF24L01+ Frequency : %d MHz\r\n", radio.getRfFrequency() );
pc.printf( "nRF24L01+ Output power : %d dBm\r\n", radio.getRfOutputPower() );
pc.printf( "nRF24L01+ Data Rate : %d kbps\r\n", radio.getAirDataRate() );
pc.printf( "nRF24L01+ TX Address : 0x%010llX\r\n", radio.getTxAddress() );
pc.printf( "nRF24L01+ RX0 Address : 0x%010llX\r\n", radio.getRxAddress(NRF24L01P_PIPE_P0) );
pc.printf( "nRF24L01+ RX1 Address : 0x%010llX\r\n", radio.getRxAddress(NRF24L01P_PIPE_P1) );
radio.setTransferSize(TRANSFER_SIZE, NRF24L01P_PIPE_P0);
radio.setTransferSize(TRANSFER_SIZE, NRF24L01P_PIPE_P1);
radio.setReceiveMode();
radio.enable();
};
bool movement_detected = false;
std::vector<std::string> last_wireless_data;
time_t last_wireless_time;
void processWirelessData(char* data_string){
std::string s = data_string;
std::vector<std::string> data;
size_t pos = 0;
std::string token;
std::string delimiter = "&";
while ((pos = s.find(delimiter)) != std::string::npos) {
token = s.substr(0, pos);
data.push_back(token);
s.erase(0, pos + delimiter.length());
}
last_wireless_data = data;
last_wireless_time = time(NULL);
if (data.size() >= 3){
double min = atof(data[0].c_str());
double max = atof(data[1].c_str());
double avg = atof(data[2].c_str());
if (max > 0.3 && avg > 0.1)
movement_detected = true;
else
movement_detected = false;
}
}
void radio_recv(){
char rxData[TRANSFER_SIZE+1];
int rx_bytes=0;
if(radio.readable(NRF24L01P_PIPE_P1)){
rx_bytes = radio.read(NRF24L01P_PIPE_P1, rxData, TRANSFER_SIZE);
rxData[TRANSFER_SIZE] = '\0';
pc.printf("Received %d >>%s<<\r\n",rx_bytes, rxData);
processWirelessData(rxData);
}
}
//Handling display
void backlightTimeout();
//RtosTimer backlightTimer(&backlightTimeout, osTimerPeriodic, (void*)0);
Timeout backlightTimer;
class Display{
public:
int wifi_on;
int alarm_on;
int sync_in_progress;
int wireless_in_progress;
int frame;
time_t seconds;
char time_str[9];
char date_str[9];
static const float backlightTime = 5.000;
int backlightState;
Display()
{
wifi_on = 0;
alarm_on = 0;
sync_in_progress = 0;
wireless_in_progress = 0;
frame = 0;
backlightState = 0;
lcd.setCursor(TextLCD::CurOff_BlkOff);
lcd.setUDC(C_ALRM, cc_dzwonek);
lcd.setUDC(C_WIFI, cc_wifi);
lcd.setUDC(C_WLC , cc_wireless);
}
void backlightOff(){
lcd.setBacklight(TextLCD::LightOff);
backlightState = 0;
}
void backlightOn(){
lcd.setBacklight(TextLCD::LightOn);
backlightState = 1;
backlightTimer.attach(&backlightTimeout, backlightTime);
}
void update(){
//Top row of display
char ico1 = ' ';
char ico2 = sync_in_progress ? (frame % 2 ? C_WIFI : ' ' ) : ' ';
char ico3 = ' ';
char alarm_time[6];
if (next_alarm != 0){
ico3 = C_ALRM;
strftime(alarm_time, 6, "%H:%M", localtime(&next_alarm));
}
else {
strcpy(alarm_time, " ");
}
time_t seconds_now = time(NULL);
if (seconds_now != seconds) {
seconds = seconds_now;
strftime(time_str, 9, "%X", localtime(&seconds));
strftime(date_str, 9, "%x", localtime(&seconds));
}
lcd.locate(0,0); //Put in top row
lcd.printf("%s%c%c%c%s",time_str,ico1,ico2,ico3,alarm_time);
lcd.locate(0,1); //Put in bottom row
if (sync_in_progress) {
lcd.printf("Synchronizacja..");
}
if (alarm_on){
lcd.printf("Wstawaj! ");
}
else {
if (frame % 60 < 30) {
lcd.printf("SmartAlarm+ Pro ");
}
else {
lcd.printf(" %08s ", date_str);
}
}
frame++;
}
};
Display disp;
//Handling user button presses
InterruptIn button(D6);
int userButtonLongPress = 300; //Time in ms; threshold for long press
Timer userButtonTimer;
int userButtonPressed = 0, userButtonReleased = 0, backlightTimedOut = 0;
void userButtonPress(){
userButtonPressed = 1;
}
void userButtonRelease(){
userButtonReleased = 1;
}
void backlightTimeout(){
backlightTimedOut = 1;
}
//Wi-Fi communication
#define WIFI_SIZE 1000
Serial wifi(PA_9, PA_10);
char wifiData[WIFI_SIZE];
bool wifiDataReady = false;
bool readInProgress = false;
int currentReadIndex = 0;
void wifiCallback() {
char c = wifi.getc();
if (c == '*') {
readInProgress = !readInProgress;
wifiData[currentReadIndex] = '\0';
currentReadIndex = 0;
if (readInProgress == false)
wifiDataReady = true;
} else if (readInProgress) {
wifiData[currentReadIndex++] = c;
}
}
std::string wifiGetData(){
if (!wifiDataReady)
return "";
std::string result = wifiData;
wifiDataReady = false;
return result;
}
std::string httpGETWithRetry(const char* query, float timeout, int retries){
Timer t;
for (int retry = 0; retry<retries; retry++){
wifi.printf(query);
t.reset();
t.start();
while (!wifiDataReady && t <= timeout){
wait(0.01f);
}
pc.printf("http GET trying #%d\r\n", retry);
if (wifiDataReady)
break;
}
return wifiGetData();
}
//Synchronization
time_t next_sync = 0;
time_t last_sync = 0;
bool sync_in_progress = false;
time_t getNextSync(){
//TODO: zmiennej czasu nie powinno sie chyba tak modyfikowac
return time (NULL) + 23;
}
int syncFunction(){
disp.sync_in_progress = 1;
last_sync = time(NULL);
std::string time_string = httpGETWithRetry("GET "
"/time/current/ "
"HTTP/1.1\r\n"
"Host: 10.1.8.202:8080\r\n\r\n", 2.0, 5);
if (time_string == ""){
//TODO: błąd synchronizacji
}
else {
set_time(atoi(time_string.c_str()));
}
time_string = httpGETWithRetry("GET "
"/alarm/get/nearest/id/5881e409e93a2218d42fe888 "
"HTTP/1.1\r\n"
"Host: 10.1.8.202:8080\r\n\r\n", 2.0, 5);
if (time_string == ""){
}
else {
next_alarm = atoi(time_string.c_str());
}
time_t now;
time(&now);
char time_str[50];
strftime(time_str, 50, "%FT%TZ", gmtime(&now));
//Get light sensor data
double light_sensor_avg;
light_sensor_avg = light_samples == 0 ? 0 : light_sum / light_samples ;
light_sum = 0;
light_samples = 0;
wifi.printf("POST "
"/alarm/get/nearest/id/5881e409e93a2218d42fe888 "
"HTTP/1.1\r\n"
"Host: 10.1.8.202:8080\r\n\r\n"
"{"
"\"date\":\"%s\""
"\"value\":%f"
"\"device_id\":\"5881e409e93a2218d42fe888\""
"\"type\":\"light\""
"}\r\n\r\n", time_str, light_sensor_avg);
next_sync = getNextSync();
return 0;
}
//Alarm
PwmOut sound(D13);
bool alarm_playing = false;
bool alarm_stopped = false;
const int* freq = axelf_freq;
const int* per = axelf_per;
int next_note = 0;
void play_next_note();
Timeout next_note_timeout;
void start_alarm(){
disp.alarm_on = 1;
alarm_playing = true;
next_note = 0;
next_note_timeout.attach(&play_next_note, 0.01);
}
void stop_alarm(){
next_alarm = 0;
alarm_playing = false;
disp.alarm_on = 0;
sound = 0.0f;
}
//TODO: won't work if melody contains -1 per at the beginning, has to have at least one note
void play_next_note(){
if (!alarm_playing)
return;
const float bpm = 100.0f; //tempo
const float base_period = 0.5f;
const float base_time = bpm / 60.0f;
if (per[next_note] <= 0)
next_note = 0;
if (freq[next_note] != 0) {
sound.period(base_period/freq[next_note]);
sound = 0.5f;
}
else {
sound = 0.0f;
}
next_note++;
next_note_timeout.attach(&play_next_note, base_time/per[next_note]);
}
int main() {
wifi.baud(115200);
wifi.attach(&wifiCallback);
//Initialization
disp.backlightOn();
button.rise(&userButtonPress);
button.fall(&userButtonRelease);
pc.printf("Waiting for time\r\n");
std::string time_string = httpGETWithRetry("GET "
"/time/current/ "
"HTTP/1.1\r\n"
"Host: 10.4.8.136:8080\r\n\r\n", 5.0, 5);
pc.printf("Get time returned >>%s<< %d\r\n", time_string.c_str());
if (time_string == ""){
lcd.locate(0,1); //Put in top row
lcd.printf("Blad synchroniz.");
wait(1);
set_time(1256729737); //DEBUG: Set RTC time to Wed, 28 Oct 2009 11:35:37
}
else {
set_time(atoi(time_string.c_str()));
}
initRadio(6, NRF24L01P_TX_PWR_ZERO_DB, NRF24L01P_DATARATE_250_KBPS);
while (1){
pc.printf("ok\r\n");
//Handling button presses
if (userButtonPressed) {
userButtonPressed = 0;
userButtonTimer.reset();
userButtonTimer.start();
}
if (userButtonReleased) {
userButtonReleased = 0;
userButtonTimer.stop();
if (userButtonTimer.read_ms() > userButtonLongPress){
pc.printf("User button long pressed");
disp.backlightOff(); //that was just debug code anyway
if (alarm_playing){
stop_alarm();
}
else {
//Force synchronization
next_sync = time(NULL);
}
}
else {
pc.printf("User button short pressed");
disp.backlightOn();
}
}
//Handling backlight
if (backlightTimedOut){
backlightTimedOut = 0;
disp.backlightOff();
}
if (time(NULL) >= next_light){
lightSensor();
}
//Synchronize with server
if (time(NULL) >= next_sync){
disp.sync_in_progress = 1;
disp.update();
syncFunction();
disp.sync_in_progress = 0;
disp.update();
}
//Check if alarm should be played
if (next_alarm != 0 && !alarm_playing){
if (time(NULL) >= next_alarm-(15*60) ){ //Hardcoded to 15 minutes before set time
if (movement_detected || time(NULL) >= next_alarm){
start_alarm();
}
}
}
//Try to receive from radio
radio_recv();
//Updating display
disp.update();
wait_ms(100);
};
}

