#include #include #include #include #include #include "serial.h" #include "writepin.h" #include "eeprom.h" #include "bitrep.h" #include "watchdog.h" #include "staticvector.h" #include "W433DataReciver.h" #include "CL56.h" #include "buttons.h" #include "ds1302.h" #include "sensor.h" #include "pwm.h" #include "dht11.h" #include "WirelessRelay.h" //#define HAS_DHT #define HAS_TRANSMITTER //#define HAS_RECIVER #define MAX_SENSORS 32 #define COMMAND_BUFFER_SIZE 64 #define SNPRINTF_BUFFER_SIZE 96 #define welcomeString "HELO " static constexpr bool bdayMsg = false; void buttonHandler(uint8_t index, uint8_t type, void* data); SVector sensors; ShiftReg<16> shiftReg(&PORTB, PB3, PB2, PB1); DS1302 clock(&PORTC, &PINC, &DDRC, PC0, PC2, PC1); DualCl56 display(&shiftReg); Buttons buttons(&buttonHandler); #ifdef HAS_DHT #define DPY_FIXED_ITEMS 4 #else #define DPY_FIXED_ITEMS 2 #endif static constexpr uint8_t almA = 0b01; static constexpr uint8_t almB = 0b10; uint8_t displaying = 0; uint8_t alm = 0; volatile bool setting = false; volatile int8_t settingOffset = 0; volatile bool ringging = false; char buffer[SNPRINTF_BUFFER_SIZE]; volatile bool sensorsPaused = true; volatile bool relaySetting = false; volatile uint8_t timer = 0; ISR(INT1_vect) { W433DataReciver::staticInterrupt(); } ISR(TIMER2_OVF_vect) { display.tick(); buttons.tick(); if(ringging && ((timer % 4 == 0 && timer < 128) || (timer > 128 && timer % 16 == 0)) ) writePin(&PORTD, PD4, true); else writePin(&PORTD, PD4, false); ++timer; } void buttonHandler(uint8_t index, uint8_t type, void* data) { if(!setting) { if(index == 0 && type == Buttons::RELEASED) { if(++displaying < sensors.count()+DPY_FIXED_ITEMS); else displaying = 0; } else if(index == 0 && type == Buttons::LONG_PRESSED) { relaySetting = !relaySetting; } else if(index == 1 && type == Buttons::RELEASED ) { if(!ringging) if(++alm > 3) alm = 0; else ringging = false; } else if(index == 1 && type == Buttons::LONG_PRESSED ) { setting = true; } } else { if(index == 1 && type == Buttons::LONG_PRESSED ) setting = false; else if(index == 0 && type == Buttons::RELEASED ) settingOffset += 10; else if(index == 1 && type == Buttons::RELEASED ) settingOffset -= 1; } } void printSensor(const Sensor& sensor, Serial* serial) { serial->write_p(PSTR("SENSOR TYPE: ")); serial->write(sensor.type); serial->write_p(PSTR(" ID: ")); serial->write(sensor.id); if(sensor.type == 1) serial->write_p(PSTR(" TEMPERATURE: ")); else if(sensor.type == 2) serial->write_p(PSTR(" HUMIDITY: ")); else serial->write_p(PSTR(" FIELD: ")); serial->write(sensor.field); serial->putChar('\n'); } void packetHandler(uint32_t packet, void* data) { Serial* serial = reinterpret_cast(data); Sensor sensor; sensor.field = packet & 0x0000FFFF; sensor.type = packet >> 24; sensor.id = (packet & 0x00FF0000) >> 16; bool found = false; for(uint8_t i = 0; i < sensors.count() && !found; ++i) { if(sensors[i] == sensor) { sensors[i] = sensor; found = true; } } if(!found) sensors.push_back(sensor); if(!sensorsPaused) printSensor(sensor, serial); } void reciverError(uint8_t code, void* userData) { if(!sensorsPaused) { Serial* serial = reinterpret_cast(userData); serial->write_p(PSTR("RECV ERROR CODE: ")); serial->write(code); serial->putChar('\n'); } } inline static void printHelp(Serial* serial) { serial->write_p(PSTR("Available Commands: \n\ help : Show this prompt.\n\ date : Show current date and time.\n\ set [yyyy] [mm] [dd] [hh] [mm] [ss] : Show current date and time.\n\ pause : pause sensor output.\n\ resume : resume sensor output.\n\ dump : Dump epprom.\n\ free : Show free ram.\n\ beep : Test buzzer.\n\ list : List sensors.\n")); } int freeRAM() { extern int __heap_start, *__brkval; int v; return (int) &v - (__brkval == 0 ? (int) &__heap_start: (int) __brkval); } void serialDispatch(Serial* serial, SVector* sensors) { if(serial->dataIsWaiting()) { char buffer[COMMAND_BUFFER_SIZE]; unsigned int length = serial->getString(buffer, COMMAND_BUFFER_SIZE); if(length > 2) { char* token = strtok(buffer, " \n"); if(strcmp(token, "date") == 0) { DS1302::Timeval time = clock.getTime(); snprintf(buffer, SNPRINTF_BUFFER_SIZE, "%04u.%02u.%02u %02u:%02u:%02u\n", time.year, time.month, time.day, time.hour, time.min, time.sec); serial->write(buffer, SNPRINTF_BUFFER_SIZE); } else if(strcmp(token, "set") == 0) { char* year = strtok(NULL, " \n"); char* mon = strtok(NULL, " \n"); char* day = strtok(NULL, " \n"); char* hour = strtok(NULL, " \n"); char* min = strtok(NULL, " \n"); char* sec = strtok(NULL, " \n"); if(year != NULL && mon != NULL && day != NULL && hour != NULL && min != NULL && sec != NULL) { DS1302::Timeval time = {atoi(sec),atoi(min),atoi(hour),atoi(day),atoi(mon),atoi(year)}; clock.setTime(time); serial->write_p(PSTR("date and time set\n")); display.setString("SET "); _delay_ms(1000); } else serial->write_p(PSTR("usage: set [yyyy] [mm] [dd] [hh] [mm] [ss]\n")); } else if(strcmp(token, "pause") == 0) { sensorsPaused = true; serial->write_p(PSTR("Sensors paused\n")); } else if(strcmp(token, "resume") == 0) { sensorsPaused = false; serial->write_p(PSTR("Sensors resumed\n")); } else if(strcmp(token, "list") == 0) { serial->write_p(PSTR("Sensors:\n")); for(uint8_t i = 0; i < sensors->count(); ++i) printSensor(sensors->at(i), serial); serial->write('\n'); } else if(strcmp(token, "erase") == 0) { for(uint16_t i = 0; i < 1024; i++) EEPROM_write_char(i, 0); serial->write_p(PSTR("EEPROM erased\n")); } else if(strcmp(token, "dump") == 0) { for(uint16_t i = 0; i < 1024; i++) { if(i != 0) serial->putChar(','); serial->write((uint16_t)EEPROM_read_char(i)); } serial->putChar('\n'); } else if(strcmp(token, "free") == 0) { serial->write_p(PSTR("Free Ram: ")); serial->write(freeRAM()); serial->write_p(PSTR(" Bytes.\n")); } else if(strcmp(token, "beep") == 0) { serial->write_p(PSTR("Beeping\n")); ringging = true; _delay_ms(1000); serial->write_p(PSTR("Done\n")); ringging = false; } else if(strcmp(token, "help") == 0) { printHelp(serial); } else serial->write_p(PSTR("Not a valid command\n")); } } } void displayItems(const DS1302::Timeval& time, int16_t temp, int16_t humid) { switch(displaying) { case 0: writePin(&PORTB, PB4, time.sec % 2); snprintf(buffer, 9, " %02u%02u", time.hour, time.min); display.setString(buffer); display.setSegments((alm & almA ? DualCl56::SEG_A : 0) | (alm & almB ? DualCl56::SEG_D : 0), 0); break; case 1: writePin(&PORTB, PB4, false); snprintf(buffer, 9, "%02u%02u%04u", time.day, time.month, time.year); display.setString(buffer, DualCl56::DP_B | DualCl56::DP_D); break; #ifdef HAS_DHT case 2: writePin(&PORTB, PB4, false); snprintf(buffer, 9, "0 1%4u", temp); display.setString(buffer, DualCl56::DP_G); break; case 3: writePin(&PORTB, PB4, false); snprintf(buffer, 9, "0 2%4u", humid); display.setString(buffer, DualCl56::DP_G); break; #endif default: writePin(&PORTB, PB4, false); snprintf(buffer, 9, "%u%3u%4u", sensors[displaying-DPY_FIXED_ITEMS].id, sensors[displaying-DPY_FIXED_ITEMS].type, sensors[displaying-DPY_FIXED_ITEMS].field); display.setString(buffer, sensors[displaying-DPY_FIXED_ITEMS].type == 1 || sensors[displaying-2].type == 2 ? DualCl56::DP_G : 0); } } void setAlarm(DS1302::Timeval* alarm, uint8_t leadingSegment = 0) { writePin(&PORTB, PB4, true); while(setting) { if(settingOffset+alarm->min > 59) { if(++alarm->hour > 23) alarm->hour = 0; alarm->min = settingOffset+alarm->min-60; } else if(settingOffset+alarm->min < 0) { if(alarm->hour-1 < 0) alarm->hour = 24; --alarm->hour; alarm->min = settingOffset+alarm->min+60; } else alarm->min += settingOffset; settingOffset = 0; snprintf(buffer, 9, "S %02u%02u", alarm->hour, alarm->min); display.setString(buffer); display.setSegments(leadingSegment, 1); } writePin(&PORTB, PB4, false); } int main() { DDRB = (1 << PB1) | ( 1 << PB2) | ( 1 << PB3) | ( 1 << PB4) | ( 1 << PB5); DDRD = (1<(128); DS1302::Timeval alarmB = EEPROM_read_class(128+64); DS1302::Timeval time = clock.getTime(); alm = EEPROM_read_char(0); uint8_t oldAlm = alm; #ifdef HAS_TRANSMITTER char name[] = "relay"; WirelessRelay relay(0b1011010001000000, name); #endif #ifdef HAS_DHT Dht11 sensor(&PORTD, &PIND, &DDRD, PD2); #endif if(time.day == 28 && time.month == 5) { if constexpr(bdayMsg) { display.setString("HAPPY "); _delay_ms(1000); display.setString("b-DAY "); _delay_ms(1000); display.setString("SASA "); _delay_ms(1000); } } else { display.setString(welcomeString); _delay_ms(1000); } #ifdef HAS_DHT sensor.read(); _delay_ms(1000); sensor.read(); #endif W433DataReciver reciver(&PIND, PD3, &TCNT1, &TIFR1, &packetHandler, reinterpret_cast(&serial), &reciverError); uint8_t deleteDate = 0; serial.write_p(PSTR("Ready\n")); uint16_t i = 0; bool oldRelaySetting = false; while(true) { #ifdef HAS_DHT if((displaying == 2 || displaying == 3) && i%2048 == 0) { cli(); sensor.read(); sei(); } #endif if(alm != oldAlm) { oldAlm = alm; EEPROM_write_char(0, alm); } #ifdef HAS_TRANSMITTER if(oldRelaySetting != relaySetting) { writePin(&PORTB, PB4, false); oldRelaySetting = relaySetting; relay.setValue(relaySetting); display.setString( relaySetting ? "RLY ON " : "RLY OFF "); _delay_ms(1000); } #endif if(setting) { setAlarm(&alarmA, DualCl56::SEG_A); setting = true; setAlarm(&alarmB, DualCl56::SEG_D); EEPROM_write_class(128, alarmA); EEPROM_write_class(128+64, alarmB); } time = clock.getTime(); #ifdef HAS_DHT displayItems(time, sensor.temperature, sensor.humidity); #else displayItems(time, 0, 0); #endif if(time.hour == alarmA.hour && time.min == alarmA.min && time.sec == 0) { ringging = true; } if(time.hour == alarmB.hour && time.min == alarmB.min && time.sec == 0) { #ifdef HAS_TRANSMITTER relay.setValue(true); #else ringging = true; #endif } #ifdef HAS_RECIVER serialDispatch(&serial, &sensors); if(deleteDate != time.day) { displaying = 0; sensors.clear(); deleteDate = time.day; display.setString("CLEAR "); _delay_ms(1000); } #endif ++i; } return 0; }