inline void timeservice_timer_handler(device_data_timeservice *p, uint8_t zyklus) { if (zyklus != 1) return; // 1s-Zyklus verwendet // Increment our counter if (p->last_time_frame_received < 255) p->last_time_frame_received++; // Check, if the time we wait for an time frame has elapsed if (p->last_time_frame_received >= p->config.takeover_time) { // time has elapsed: We did not receive any time frame // which had a lower level than us in the given takeover_time // // So, we will become the time master. if (p->last_time_frame_sent++ == p->config.interval) { canix_frame message; // The end of the interval has been reached, so send a new // time frame because we are the master ! p->last_time_frame_sent = 0; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_INFO; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_RTS; message.data[1] = HCAN_RTS_TIME_INFO; message.data[2] = p->config.level; message.data[3] = canix_rtc_clock.day_of_week; message.data[4] = canix_rtc_clock.hour; message.data[5] = canix_rtc_clock.minute; message.data[6] = canix_rtc_clock.second; message.size = 7; canix_frame_send(&message); // ... and send the date message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_INFO; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_RTS; message.data[1] = HCAN_RTS_DATE_INFO; message.data[2] = p->config.level; message.data[3] = canix_rtc_clock.day_of_month; message.data[4] = canix_rtc_clock.month_of_year; message.data[5] = canix_rtc_clock.year; message.size = 6; canix_frame_send(&message); } } }
void powerport_page_print_page(eds_powerport_page_block_t *p) { char s[40]; canix_frame message; // LCD Bildschirm loeschen lcd_clrscr(); // 1. Zeile snprintf_P(s,sizeof(s), PSTR("%s"), p->line0); lcd_gotoxy(0,0); lcd_puts(s); snprintf_P(s,sizeof(s), PSTR("%s"), p->line1); lcd_gotoxy(0,1); lcd_puts(s); // In powerport_page_state wird spaeter der State gespeichert; sollte // keine Meldung eintreffen, so nuetzt es nichts, wenn der User OK // drueckt - man weiss ja den State nicht und kann ihn nicht aendern! // Das erkennt man am Wert -1 powerport_page_state = -1; powerport_page_timer = -1; // nun den Status des Powerports erfragen und (asynchron) // in powerport_page_can_callback weitermachen message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_POWER_GROUP_STATE_QUERY; message.data[2] = p->gruppe; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); canix_sleep_100th(1); message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_POWER_GROUP_TIMER_QUERY; message.data[2] = p->gruppe; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); }
void rolladen_page_handle_key_down_event(eds_rolladen_page_block_t *p, uint8_t key) { if (key == KEY_OK) { canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_ROLLADEN_POSITION_SET; message.data[2] = p->gruppe; message.data[3] = p->pos; message.size = 4; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); lcdctrl_blink(); return; } if (key == KEY_ESC) { goto_page_up(); return; } if (key == KEY_UP) goto_prev_page(); if (key == KEY_DOWN) goto_next_page(); }
static inline void sendMessage(device_data_schalter *p, uint8_t active) { canix_frame message; if(active) p->lastEdge = RISING; else p->lastEdge = FALLING; if(p->config.feature & (1<<FEATURE_SCHALTER_INVERTIEREN)) active = !active; // invertieren message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; if(active) { if(p->config.feature & (1<<FEATURE_SCHALTER_MUTE)) message.data[1] = HCAN_HES_MUTE_ON; else message.data[1] = HCAN_HES_SCHALTER_ON; } else { if(p->config.feature & (1<<FEATURE_SCHALTER_MUTE)) message.data[1] = HCAN_HES_MUTE_OFF; else message.data[1] = HCAN_HES_SCHALTER_OFF; } message.data[2] = p->config.gruppe; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); }
uint8_t get_weck_details(uint8_t weck_id, uint16_t *dauer) { canix_frame message; weck_details_weck_id = weck_id; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_WECKER_DETAILS_REQUEST; message.data[2] = weck_id; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); weck_details_expected = 1; // Bit 0 = HCAN_HES_WECKER_DETAILS_REQUEST // Auf die Anwort warten canix_sleep_100th(5); if (weck_details_expected == 0) { // aha, es ist eine Antwort eingetroffen... (und zwar HCAN_HES_WECKER_DETAILS) *dauer = weck_details_dauer; weck_details_weck_id = 0; return 0; } // Timeout... keine Antwort erhalten :-( return 1; }
void set_weck_edited_details(eds_weck_page_block_t *p) { canix_frame message; // 1. herausfinden, welcher Parameter geaendert wurde message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_WECKER_SET; message.data[2] = p->weck_id; //=Powerport-Gruppe message.data[3] = POWERPORT_FEATURE_WECK_VERZOEGERT_EIN; //Vorbelegung if ( p->feature & (1<<POWERPORT_FEATURE_WECK_VERZOEGERT_EIN) ) { message.data[3] = POWERPORT_FEATURE_WECK_VERZOEGERT_EIN; } else if ( p->feature & (1<<POWERPORT_FEATURE_WECK_AUTO_AUS) ) { message.data[3] = POWERPORT_FEATURE_WECK_AUTO_AUS; } message.data[4] = weck_details_dauer_edit >> 8; //Dauer bis Wecker einschaltet message.data[5] = weck_details_dauer_edit; //LSB message.size = 6; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); }
void switch_to_battery(void) { canix_frame message; // Status merken: on_battery = 1; // Relais schalten darlingtonoutput_setpin(7,1); // Timer auf 2 Sekunden setzen, d.h. fruehstens in // 2 Sekunden kann die USV wieder reagieren. Das ist noetig // damit kein "Prellen" oder "Flackern" passiert usv_timer = 200; // LEDs anpassen: led_set(3,0); led_set(6,10); // Busteilnehmer informieren: message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_INFO; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_USVS; message.data[1] = HCAN_USVS_STATE_INFO; message.data[2] = on_battery; message.size = 3; canix_frame_send(&message); }
void switch_to_netzbetrieb(void) { canix_frame message; // Status merken: on_battery = 0; // Relais schalten darlingtonoutput_setpin(7,0); // Auch hier wieder: ein Prellen verhindern usv_timer = 10; // LEDs anpassen: led_set(3,10); led_set(6,0); // Busteilnehmer informieren: message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_INFO; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_USVS; message.data[1] = HCAN_USVS_STATE_INFO; message.data[2] = on_battery; message.size = 3; canix_frame_send(&message); }
void usv_can_callback(const canix_frame *frame) { canix_frame answer; answer.src = canix_selfaddr(); answer.dst = frame->src; answer.proto = HCAN_PROTO_SFP; answer.data[0] = HCAN_SRV_USVS; switch (frame->data[1]) { case HCAN_USVS_STATE_REQUEST : { answer.data[1] = HCAN_USVS_STATE_INFO; answer.data[2] = on_battery; answer.size = 3; canix_frame_send(&answer); } return; case HCAN_USVS_VOLTAGE_REQUEST : { // "- 1" : U1-U5 wird abgebildet auf 0..4 const uint8_t n = frame->data[2] - 1; if (n < 5) { uint16_t U = adc_reach_channel(n); answer.data[1] = HCAN_USVS_VOLTAGE_REPLAY; answer.data[2] = U >> 8; answer.data[3] = U; answer.size = 4; canix_frame_send(&answer); } } return; case HCAN_USVS_VOLTAGE_STATS_REQUEST : { // "- 1" : U1-U5 wird abgebildet auf 0..4 const uint8_t n = frame->data[2] - 1; if (n < 5) { answer.data[1] = HCAN_USVS_VOLTAGE_STATS_REPLAY; answer.data[2] = frame->data[2]; answer.data[3] = U_min[n] >> 8; answer.data[4] = U_min[n]; answer.data[5] = U_max[n] >> 8; answer.data[6] = U_max[n]; answer.size = 7; canix_frame_send(&answer); } }
uint8_t get_heiz_details(uint8_t heiz_id, uint8_t *mode, uint8_t *rate, int16_t *Tsoll, uint16_t *dauer, uint16_t *Tist) { canix_frame message; heiz_details_heiz_id = heiz_id; heiz_details_Tsoll = 0; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_HEIZUNG_DETAILS_REQUEST; message.data[2] = heiz_id; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); heiz_details_expected = 1; // Bit 0 = HCAN_HES_HEIZUNG_DETAILS_REQUEST // Auf die Anwort warten canix_sleep_100th(5); // ... und noch nach T(ist) fragen... message.data[1] = HCAN_HES_HEIZUNG_TIST_REQUEST; message.data[2] = heiz_id; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); heiz_details_expected = 2; // Bit 1 = HCAN_HES_HEIZUNG_TIST_REQUEST // Auf die Anwort warten canix_sleep_100th(5); if (heiz_details_expected == 0) { // aha, es ist eine Antwort eingetroffen... *mode = heiz_details_mode; *rate = heiz_details_rate; *Tsoll = heiz_details_Tsoll; *Tist = heiz_details_Tist; *dauer = heiz_details_dauer; heiz_details_heiz_id = 0; return 0; } // Timeout... keine Antwort erhalten :-( return 1; }
static inline void sendMessage(device_data_zeitschaltuhr *p, uint8_t zustandToSend) { canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = zustandToSend; message.data[2] = p->config.power_gruppe; message.size = 3; canix_frame_send(&message); }
static inline void sendMessage(device_data_zentralheizungspumpe *p, uint8_t zustandToSend) { canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = zustandToSend; // Zentralheizungspumpe schalten message.data[2] = p->config.gruppe; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); }
void send_log(uint8_t data, uint8_t data2) { canix_frame answer; answer.src = canix_selfaddr(); answer.dst = 40; answer.proto = HCAN_PROTO_SFP; answer.data[0] = 21; answer.data[1] = data; answer.data[2] = data2; answer.size = 3; canix_frame_send(&answer); delay(1); }
void send_rolladen_position_set(device_data_rolladenSchlitzpos *p, uint8_t soll_position) { canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_ROLLADEN_POSITION_SET; message.data[2] = p->config.rolladen; message.data[3] = soll_position; //gewuenschte Rollladenposition: z.B. Pos: 0=zu, SCHLITZ_POS message.size = 4; canix_frame_send_with_prio(&message, HCAN_PRIO_LOW); }
/** Der poti_timer_handler liest den ADC-Wert des * konfigurierten Potis und sendet diesen auf den CAN-Bus. */ inline void poti_timer_handler(device_data_poti *p, uint8_t zyklus) { if (zyklus != 10) return; // 10tel-Sekunden-Zyklus verwendet int16_t currentADCvalue; setADMUX(p->config.port); currentADCvalue = getADCvalue(); if (p->potiTelegramCountdown) { /* Abfrage, ob sich der ADC-Wert signifikant aenderte, * gegenueber dem Wert im letzten Potitelegramm (Filterung): */ if ( ( currentADCvalue > (p->lastPotiValue + POTI_VALUE_TOLERANCE) ) || ( currentADCvalue < (p->lastPotiValue - POTI_VALUE_TOLERANCE) ) ) { //sign. Potiwertaenderung gegenueber dem currentADCvalue p->potiTelegramCountdown--; } else { //Potiwert wieder der gleiche Wert (oder zumindest in etwa) p->potiTelegramCountdown = POTI_TELEGRAM_COUNTDOWN_INIT; } } else //p->potiTelegramCountdown == 0 { //Das Potitelegramm senden: p->lastPotiValue = currentADCvalue; //Angleich p->potiTelegramCountdown = POTI_TELEGRAM_COUNTDOWN_INIT; //sende das Potitelegramm: canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_POTI_POS_CHANGED; message.data[2] = p->config.gruppe; message.data[3] = (uint8_t)((currentADCvalue & 0xFF00) >> 8); //high value message.data[4] = (uint8_t)currentADCvalue; //low value message.size = 5; canix_frame_send_with_prio(&message, HCAN_PRIO_LOW); } }
static void rolladen_send_changed_info(device_data_rolladen *p, uint8_t pos) { canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_INFO; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_ROLLADEN_POSITION_CHANGED_INFO; message.data[2] = p->config.taster; message.data[3] = pos; // aktuelle Position in % message.data[4] = 0; // Quelle des cmd: nicht verwendet message.data[5] = 0; // Quelle des cmd: nicht verwendet message.size = 6; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); }
void canix_syslog_P(uint8_t prio, const char *fmt, ...) { if (canix_debug_level >= prio) { canix_frame message; uint8_t s_counter, payload_counter; char s[128]; va_list ap; va_start(ap, fmt); vsnprintf_P(s, sizeof(s)-2, fmt, ap); va_end(ap); // An das Ende ein Retrun Zeichen anhaengen; somit kann die // empfangende Seite erkennen, wann die Meldung beendet ist. // // Hier benoetigen wir keinen Laengen-Check, da wir oben // sizeof(s)-2 verwendet haben. strcat(s,"\n"); message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_SYSLOG; message.proto = HCAN_PROTO_SYSLOG; s_counter = 0; message.data[0] = prio; payload_counter = 1; while (s_counter < strlen(s)) { wdt_reset(); while ((payload_counter < 8) && (s_counter < strlen(s))) { message.data[payload_counter++] = s[s_counter++]; } message.size = payload_counter; payload_counter = 0; canix_frame_send(&message); } canix_sleep_100th(1); } }
inline void rolladenSchlitzpos_timer_handler(device_data_rolladenSchlitzpos *p, uint8_t zyklus) { if (zyklus != 10) return; // 10tel-Sekunden-Zyklus verwendet canix_frame message; if(p->rolladenSchlitzJob < SCHLITZ_JOB_ABGEMELDET) //ist der Job angemeldet { p->rolladenSchlitzJob--; //es sind wieder 100 ms vergangen //canix_syslog_P(SYSLOG_PRIO_DEBUG, PSTR("p->rolladenSchlitzJob=%d"), p->rolladenSchlitzJob); if(p->rolladenSchlitzJob == 0) { p->rolladenSchlitzJob = SCHLITZ_JOB_ABGEMELDET; /* Warte zwei Sekunden. Falls das Fenster wieder geoeffnet wird, * wird der rolladenSchlitzJob wieder abgemeldet, * die HCAN_HES_REEDKONTAKT_STATE_QUERY nicht gesendet * und somit der Rollladen nicht geschlossen. * ...und dann in HCAN_HES_REEDKONTAKT_STATE_REPLAY die Abfrage, * ob der Reedkontakt immer noch zu ist: */ message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_ROLLADEN_POSITION_REQUEST; message.data[2] = p->config.rolladen; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); //rolladenIstposition-Abfrage //und Reedkontakt(e) abfragen: message.data[1] = HCAN_HES_REEDKONTAKT_STATE_QUERY; message.data[2] = p->config.reed0; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_LOW); if(p->config.reed1 != 255) //zweiter Reedkontakt vorhanden? { message.data[2] = p->config.reed1; canix_frame_send_with_prio(&message, HCAN_PRIO_LOW); } } } }
/** * Fragt alle konfigurierten Reedkontakte nach ihrem Status und sammelt * die Ergebnisse in fenster_monitor_reed_state; liefert die Anzahl der * offenen Reedkontakte zurueck */ uint8_t fenster_monitor_collect_reed_states(eds_fenster_monitor_page_block_t *p) { uint8_t i,n_reed_open; uint8_t *reeds = (uint8_t *)(&p->reed0); // Ergebnis-Array initialisieren: for (i = 0; i < 24; i++) fenster_monitor_reed_state[i] = 255; // ueber alle Reedkontakte iterieren: for (i = 0; i < 24; i++) { if (reeds[i] != 255) // ist es ein konfigurierter Reedkontakt? { // Nach Kontakt-Status fragen; die Ergebnisse kommen asynchron // ueber den CAN Handler rein canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_REEDKONTAKT_STATE_QUERY; message.data[2] = reeds[i]; // die Reedkontakt-Gruppen-ID message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_LOW); canix_sleep_100th(10); // 100msec Pause } wdt_reset(); } // Reedkontakte zaehlen: n_reed_open = 0; for (i = 0; i < 24; i++) { if ((fenster_monitor_reed_state[i]) && (fenster_monitor_reed_state[i] != 255)) n_reed_open++; } return n_reed_open; }
/** * Fragt alle konfigurierten Reedkontakte nach ihrem Status und sammelt * die Ergebnisse in monitor_reedkontakt_state */ static void init_monitor_reedkontakt_request_states(void) { eds_block_p it = eds_find_next_block((eds_block_p)0, EDS_userpanel_reedkontakte_BLOCK_ID); if (!it) { load_error_page(ERROR_CONF_REEDKONTAKTE_MISSING); reedkontakt_configured = 0; return; } userpanel_reedkontakte_t c; eeprom_read_block(&c, (it+2), sizeof(c)); uint8_t i; // Ergebnis-Array initialisieren: for (i = 0; i < 24; i++) monitor_reedkontakt_state[i] = 255; // ueber alle Reedkontakte iterieren: for (i = 0; i < 24; i++) { if (c.reed[i] != 255) // ist es ein konfigurierter Reedkontakt? { // Nach Kontakt-Status fragen; die Ergebnisse kommen asynchron // ueber den CAN Handler rein canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_REEDKONTAKT_STATE_QUERY; message.data[2] = c.reed[i]; // die Reedkontakt-Gruppen-ID message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_LOW); canix_sleep_100th(10); // 100msec Pause } wdt_reset(); } }
static inline void sendMessage(device_data_powerportAutomat *p, uint8_t active) { canix_frame message; // Helligkeitssensor: if( p->automatikEin // Automatikbetrieb && (HCAN_HES_POWER_GROUP_ON == active) // HCAN_HES_POWER_GROUP_OFF soll immer moeglich sein && (p->brightness != 65535) // Helligkeitssensor verwenden? && (p->brightness > p->config.helligkeitsschwelle) ) // zu hell? { return; // zu hell -> kein HCAN_HES_POWER_GROUP_ON senden } message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = active; // HCAN_HES_POWER_GROUP_ON oder HCAN_HES_POWER_GROUP_OFF message.data[2] = p->config.powerport_gruppe; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); }
void hauselektrik_callback(const canix_frame *frame) { // Dieser Handler wird fuer alle Destination Adressen ausgefuehrt // daher muss gefiltert werden, was uns betrifft und was nicht if ( (frame->data[0] != HCAN_SRV_HES) || ((frame->dst != canix_selfaddr()) && (frame->dst != HCAN_MULTICAST_CONTROL) && (frame->dst != HCAN_MULTICAST_INFO))) { // Diese Message ist nicht interessant, daher ignorieren return; } lcdstatemachine_can_callback(frame); switch (frame->data[1]) { case HCAN_HES_CONFIG_RELOAD : return; } }
void taster_page_handle_key_down_event(eds_taster_page_block_t *p, uint8_t key) { if (key == KEY_OK) { canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_TASTER_DOWN; message.data[2] = p->gruppe; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); canix_sleep_100th(1); message.data[1] = HCAN_HES_TASTER_UP; message.size = 3; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); lcdctrl_blink(); return; } if (key == KEY_ESC) { goto_page_up(); return; } if (key == KEY_UP) goto_prev_page(); if (key == KEY_DOWN) goto_next_page(); }
/** Der helligkeitssensor_timer_handler wird alle 1 s aufgerufen: Er liest den ADC-Wert des * konfigurierten helligkeitssensors und sendet diesen auf den CAN-Bus. */ inline void helligkeitssensor_timer_handler(device_data_helligkeitssensor *p, uint8_t zyklus) { if (zyklus != 1) return; // 1s-Zyklus verwendet uint16_t currentADCaverage; if (p->secsUntilNextSend) { p->secsUntilNextSend--; // nur die letzten n Werte vorm Senden sind wichtig: if(p->secsUntilNextSend <= SIZE_OF_AVG) { setADMUX(p->config.port); addToFloatAvg(&(p->filterBrightness), getADCvalue_inverted()); } } else { currentADCaverage = getOutputValue(&(p->filterBrightness)); // sende das Helligkeitssensortelegramm: canix_frame message; message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_HELLIGKEITS_INFO; //z.B. fuer rolladenAutomat-Device message.data[2] = p->config.gruppe; message.data[3] = (uint8_t)((currentADCaverage & 0xFF00) >> 8); //high value message.data[4] = (uint8_t)currentADCaverage; //low value message.size = 5; canix_frame_send_with_prio(&message, HCAN_PRIO_LOW); p->secsUntilNextSend = (uint16_t) 60 * p->config.sendCycleMins; } }
/** * Sendet Updates an alle Action-Gruppen */ void inform_action_groups(const device_data_lichtzone *p) { canix_frame answer; uint8_t *action_group; uint8_t i; action_group = (uint8_t *)&(p->config.action_gruppe0); for (i = 0; i < 2; i++) { if (action_group[i] != 255) { answer.src = canix_selfaddr(); answer.dst = HCAN_MULTICAST_CONTROL; answer.proto = HCAN_PROTO_SFP; answer.data[0] = HCAN_SRV_HES; answer.data[1] = p->state != 0 ? HCAN_HES_POWER_GROUP_ON : HCAN_HES_POWER_GROUP_OFF; answer.data[2] = action_group[i]; answer.size = 3; canix_frame_send_with_prio(&answer, HCAN_PRIO_HI); } } }
void heizung_can_callback(device_data_heizung *p, const canix_frame *frame) { canix_frame answer; answer.src = canix_selfaddr(); answer.dst = frame->src; answer.proto = HCAN_PROTO_SFP; answer.data[0] = HCAN_SRV_HES; switch (frame->data[1]) { case HCAN_HES_1WIRE_TEMPERATURE : if (frame->data[2] == p->config.sensor_id) { // we have a heizung and a temp sensor frame // now look if if fits to the heizung // temperature is a fixed point number mit 4 LSB Bits int16_t sensor_temp = frame->data[3] << 8 | frame->data[4]; // store the measure value p->measure_value = sensor_temp; p->received_interval_counter = 0; } break; case HCAN_HES_HEIZUNG_SET_MODE_OFF : if (p->config.id == frame->data[2]) p->mode = HEIZUNG_MODE_OFF; break; case HCAN_HES_HEIZUNG_SET_MODE_MANUAL : if (p->config.id == frame->data[2]) { p->mode = HEIZUNG_MODE_MANUAL; p->manual_rate = frame->data[3]; p->duration_counter = (frame->data[4] << 8) | frame->data[5]; } break; case HCAN_HES_HEIZUNG_SET_MODE_THERMOSTAT_DETAILS : if (p->config.id == frame->data[2]) { p->mode = HEIZUNG_MODE_THERMOSTAT; p->thermostat_temp = (frame->data[3] << 8) | frame->data[4]; p->duration_counter = (frame->data[5] << 8) | frame->data[6]; } break; case HCAN_HES_HEIZUNG_SET_MODE_AUTOMATIK: if (p->config.id == frame->data[2]) p->mode = HEIZUNG_MODE_AUTOMATIK; break; case HCAN_HES_HEIZUNG_DETAILS_REQUEST : { if (p->config.id == frame->data[2]) { switch (p->mode) { case HEIZUNG_MODE_OFF : answer.data[1] = HCAN_HES_HEIZUNG_MODE_OFF_DETAILS; answer.data[2] = p->config.id; answer.size = 3; canix_frame_send_with_prio(&answer, HCAN_PRIO_HI); break; case HEIZUNG_MODE_MANUAL : answer.data[1] = HCAN_HES_HEIZUNG_MODE_MANUAL_DETAILS; answer.data[2] = p->config.id; answer.data[3] = p->manual_rate; answer.data[4] = p->duration_counter >> 8; answer.data[5] = p->duration_counter; answer.size = 6; canix_frame_send_with_prio(&answer, HCAN_PRIO_HI); break; case HEIZUNG_MODE_THERMOSTAT : answer.data[1] = HCAN_HES_HEIZUNG_MODE_THERMOSTAT_DETAILS; answer.data[2] = p->config.id; answer.data[3] = p->thermostat_temp >> 8; answer.data[4] = p->thermostat_temp; answer.data[5] = p->duration_counter >> 8; answer.data[6] = p->duration_counter; answer.size = 7; canix_frame_send_with_prio(&answer, HCAN_PRIO_HI); break; case HEIZUNG_MODE_AUTOMATIK : { int8_t index; index = heizung_get_matching_zeitzone_index(p); if (index != -1) { // we got an zeitzone which matches int16_t master_value = 0; solltemp_line_t *zeitzone = (solltemp_line_t *) &(p->config.zeitzone0_id); master_value = zeitzone[index].temp; answer.data[1] = HCAN_HES_HEIZUNG_MODE_AUTOMATIK_DETAILS; answer.data[2] = frame->data[2]; answer.data[3] = master_value >> 8; answer.data[4] = master_value; answer.data[5] = heizung_get_matching_zeitzone_id(p); answer.size = 6; } else { canix_syslog_P(SYSLOG_PRIO_ERROR, PSTR("zeitzone: no match!")); answer.data[1] = HCAN_HES_HEIZUNG_MODE_AUTOMATIK_DETAILS; answer.data[2] = frame->data[2]; answer.data[3] = 0; answer.data[4] = 0; answer.data[5] = 0; answer.size = 6; } canix_frame_send_with_prio(&answer, HCAN_PRIO_HI); } break; } } }
/** * this timer handler is called every second */ void heizung_timer_handler(device_data_heizung *p) { if (p->ventilpflege_counter > 0) p->ventilpflege_counter--; // Ventilpflege aktivieren, falls der richtige Zeitpunkt dazu ist: heizung_check_ventilpflege(p); if (p->received_interval_counter != 0xff) p->received_interval_counter++; heizung_handle_pwm(p); if (p->duration_counter > 0) { p->duration_counter -= 1; if (p->duration_counter == 0) { // Zeit ist abgelaufen; nun wieder auf Automatik-Modus // stellen: // p->mode = HEIZUNG_MODE_AUTOMATIK; } } if (p->reed_heiz_stop_counter > 0) { p->reed_heiz_stop_counter -= 1; if (p->reed_heiz_stop_counter == 0) { canix_syslog_P(SYSLOG_PRIO_DEBUG, PSTR("heiz-stop ende (heizung %d)"), p->config.id); } } /* * Schaltet die HK-Ventile aus, wenn ein Heizstop vorliegt. Dies passiert * in regelmaessigen Abstaenden, da eventuell aufgrund der Heizsteuerlogik * die PWM nicht regelmaessig upgedatet wird und so das HK-Ventil nicht auf * den Reedkontakt reagiert. */ heizung_update_heizstop(p); if (p->timer_counter++ >= 5) { p->timer_counter = 0; switch (p->mode) { case HEIZUNG_MODE_OFF : { if (p->ventilpflege_counter) { // Sonderfall: Ventilpflege ist aktiv; dazu // Ventil einschalten, sonst aber nichts // unternehmen: p->manual_rate = 0; // Ventil einschalten: heizung_set_pwm(p,100); darlingtonoutput_setpin(p->config.port, 1); canix_syslog_P(SYSLOG_PRIO_DEBUG, PSTR("ventilpflege: 1")); } else { // das ist Normalfall: keine Ventilpflege aktiv. p->manual_rate = 0; heizung_set_pwm(p,0); // Ventil ausschalten, falls es an ist: if (darlingtonoutput_getpin(p->config.port)) darlingtonoutput_setpin(p->config.port, 0); } return; } case HEIZUNG_MODE_MANUAL : { heizung_set_pwm(p, p->manual_rate); } break; case HEIZUNG_MODE_AUTOMATIK : { // Wenn ein gueltiger Messwert vorliegt // (d.h. wenn innerhalb eines definierten Zeitraumes // ein Sensor-Messwert eingetroffen ist: if (p->received_interval_counter < 255) { int8_t index; index = heizung_get_matching_zeitzone_index(p); if (index != -1) { // we got an zeitzone which matches solltemp_line_t *solltemp_line = (solltemp_line_t*) &(p->config.zeitzone0_id); heizung_set_pwm_by_temp(p, solltemp_line[index].temp, p->measure_value); } else { // keine passende Zeitzone gefunden heizung_set_pwm(p,0); } } else { canix_syslog_P(SYSLOG_PRIO_ERROR, PSTR("keine Sensor-Messwerte vorhanden!")); } } break; case HEIZUNG_MODE_THERMOSTAT : { // Wenn ein gueltiger Messwert vorliegt // (d.h. wenn innerhalb eines definierten Zeitraumes // ein Sensor-Messwert eingetroffen ist: if (p->received_interval_counter < 255) { heizung_set_pwm_by_temp(p, p->thermostat_temp, p->measure_value); } else { canix_syslog_P(SYSLOG_PRIO_ERROR, PSTR("keine Sensor-Messwerte vorhanden!")); } } break; } } // Waermebedarfsmeldung versenden: if (p->waermebedarf_counter-- == 0) { canix_frame message; // Waermebedarfsmeldungen alle 60 Sekunden p->waermebedarf_counter = 60; // den aktuellen Ventilstand / Heizrate ermitteln: uint8_t rate = heizung_get_pwm(p); // Feature-Bit testen, und ggfls Waermebedarf verdoppeln: if (p->config.feature & (1<<HEIZUNG_FEATURE_DOPPEL_WAERMEBEDARF)) rate = rate << 1; // Der Waermebedarf ist proportional zur Ventilstellung, d.h. // der Bedarf ist hoch, wenn das Ventil voll offen ist, und ist // nicht vorhanden, wenn das Ventil zu ist. message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_INFO; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; message.data[1] = HCAN_HES_HEIZUNG_WAERMEBEDARF_INFO; message.data[2] = p->config.id; message.data[3] = rate; message.size = 4; canix_frame_send_with_prio(&message, HCAN_PRIO_LOW); } }
void set_heiz_edited_details(eds_heiz_page_block_t *p) { canix_frame message; // 1. wir muessen anhand er subpage herausfinden, welcher Parameter // geaendert wurde message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; switch (heiz_page_subpage) { case 0 : // hier wurde der Modus geaendert. Das bedeutet, dass wir // die Parameter, die dieser Modus beinhaltet, nicht kennen und // erstmal Defaults senden muessen. Der Benutzer kann dann // diese Parameter finetunen, wenn der Modus gewechselt ist. switch (heiz_details_mode_edit) { case HEIZUNG_MODE_OFF : message.data[1] = HCAN_HES_HEIZUNG_SET_MODE_OFF; message.data[2] = p->heiz_id; message.size = 3; break; case HEIZUNG_MODE_MANUAL : message.data[1] = HCAN_HES_HEIZUNG_SET_MODE_MANUAL; message.data[2] = p->heiz_id; message.data[3] = 0; message.data[4] = 84; message.data[5] = 96; // Dauer: 6h message.size = 6; break; case HEIZUNG_MODE_THERMOSTAT : message.data[1] = HCAN_HES_HEIZUNG_SET_MODE_THERMOSTAT_DETAILS; message.data[2] = p->heiz_id; message.data[3] = 1; message.data[4] = 64; // 20 Grad ist Standard message.data[5] = 84; message.data[6] = 96; // Dauer: 6h message.size = 7; break; case HEIZUNG_MODE_AUTOMATIK : message.data[1] = HCAN_HES_HEIZUNG_SET_MODE_AUTOMATIK; message.data[2] = p->heiz_id; message.size = 3; break; } break; case 1 : case 2 : if (heiz_details_mode_edit == HEIZUNG_MODE_MANUAL) { message.data[1] = HCAN_HES_HEIZUNG_SET_MODE_MANUAL; message.data[2] = p->heiz_id; message.data[3] = heiz_details_rate_edit; message.data[4] = heiz_details_dauer_edit >> 8; message.data[5] = heiz_details_dauer_edit; message.size = 6; break; } if (heiz_details_mode_edit == HEIZUNG_MODE_THERMOSTAT) { message.data[1] = HCAN_HES_HEIZUNG_SET_MODE_THERMOSTAT_DETAILS; message.data[2] = p->heiz_id; message.data[3] = heiz_details_Tsoll_edit >> 8; message.data[4] = heiz_details_Tsoll_edit; message.data[5] = heiz_details_dauer_edit >> 8; message.data[6] = heiz_details_dauer_edit; message.size = 7; break; }
void canix_SFP_HMS_handler(const canix_frame *frame) { canix_frame answer; answer.src = canix_selfaddr(); answer.dst = frame->src; answer.proto = HCAN_PROTO_SFP; answer.data[0] = HCAN_SRV_HMS; switch (frame->data[1]) { case HCAN_HMS_PING_REQUEST : answer.data[1] = HCAN_HMS_PING_REPLAY; answer.size = 2; canix_frame_send(&answer); break; case HCAN_HMS_DEVICE_STATE_REQUEST : answer.data[1] = HCAN_HMS_DEVICE_STATE_REPLAY; answer.data[2] = HCAN_HMS_DEV_STATE_APPLICATION; answer.size = 3; canix_frame_send(&answer); break; case HCAN_HMS_DEVICE_RESET : canix_reset(); break; case HCAN_HMS_DEVICE_TYPE_REQUEST : answer.data[1] = HCAN_HMS_DEVICE_TYPE_REPLAY; #if defined (__AVR_ATmega8__) answer.data[2] = 0; #elif defined (__AVR_ATmega32__) answer.data[2] = 1; #elif defined (__AVR_ATmega644__) answer.data[2] = 2; #endif answer.data[3] = eeprom_read_byte((uint8_t *)EEPR_BOARD_TYPE); answer.size = 4; canix_frame_send(&answer); break; case HCAN_HMS_INTERNAL_EEPROM_WRITE : { // only write to eeprom, if the value changed ! uint8_t read = eeprom_read_byte((uint8_t *)(frame->data[2] | (frame->data[3] << 8))); if (read != frame->data[4]) eeprom_write_byte((uint8_t *)(frame->data[2] | (frame->data[3] << 8)), frame->data[4]); answer.data[1] = HCAN_HMS_INTERNAL_EEPROM_WRITE_ACK; answer.size = 2; canix_frame_send(&answer); } break; case HCAN_HMS_INTERNAL_EEPROM_READ_REQUEST : answer.data[1] = HCAN_HMS_INTERNAL_EEPROM_READ_REPLAY; answer.data[2] = eeprom_read_byte((uint8_t *)(frame->data[2] | (frame->data[3] << 8))); answer.size = 3; canix_frame_send(&answer); break; case HCAN_HMS_INTERNAL_EEPROM_READ_BULK_REQUEST : { uint16_t address; address = frame->data[2] | (frame->data[3] << 8); answer.data[1] = HCAN_HMS_INTERNAL_EEPROM_READ_BULK_REPLAY; answer.data[2] = eeprom_read_byte((uint8_t*) (address + 0)); answer.data[3] = eeprom_read_byte((uint8_t*) (address + 1)); answer.data[4] = eeprom_read_byte((uint8_t*) (address + 2)); answer.data[5] = eeprom_read_byte((uint8_t*) (address + 3)); answer.data[6] = eeprom_read_byte((uint8_t*) (address + 4)); answer.data[7] = eeprom_read_byte((uint8_t*) (address + 5)); answer.size = 8; canix_frame_send(&answer); } break; case HCAN_HMS_UPTIME_QUERY : answer.size = 6; answer.data[1] = HCAN_HMS_UPTIME_REPLAY; answer.data[2] = canix_rtc_clock.uptime_sec >> 24; answer.data[3] = canix_rtc_clock.uptime_sec >> 16; answer.data[4] = canix_rtc_clock.uptime_sec >> 8; answer.data[5] = canix_rtc_clock.uptime_sec; canix_frame_send(&answer); break; case HCAN_HMS_SYSLOG_LEVEL_SET : #ifdef CANIX_SYSLOG canix_set_syslog_level(frame->data[2]); eeprom_write_byte((uint8_t *)EEPR_DEBUG_LEVEL, frame->data[2]); #endif break; case HCAN_HMS_BUILD_VERSION_QUERY : answer.data[1] = HCAN_HMS_BUILD_VERSION_REPLAY; answer.data[2] = #include <buildver> >> 8; answer.data[3] = #include <buildver> ; answer.size = 4; canix_frame_send(&answer); break; case HCAN_HMS_CAN_EC_QUERY : { uint16_t ec = can_error_counters(); answer.data[1] = HCAN_HMS_CAN_EC_REPLAY; answer.data[2] = ec >> 8; answer.data[3] = ec; answer.size = 4; canix_frame_send(&answer); } break; case HCAN_HMS_RX_RECEIVED_QUERY : { answer.data[1] = HCAN_HMS_RX_RECEIVED_REPLAY; answer.data[2] = canix_rx_received >> 24; answer.data[3] = canix_rx_received >> 16; answer.data[4] = canix_rx_received >> 8; answer.data[5] = canix_rx_received; answer.size = 6; canix_frame_send(&answer); } break; case HCAN_HMS_RX_LOST_QUERY : { answer.data[1] = HCAN_HMS_RX_LOST_REPLAY; answer.data[2] = canix_rx_lost >> 24; answer.data[3] = canix_rx_lost >> 16; answer.data[4] = canix_rx_lost >> 8; answer.data[5] = canix_rx_lost; answer.size = 6; canix_frame_send(&answer); } break; case HCAN_HMS_TX_SENT_QUERY : { answer.data[1] = HCAN_HMS_TX_SENT_REPLAY; answer.data[2] = canix_tx_sent >> 24; answer.data[3] = canix_tx_sent >> 16; answer.data[4] = canix_tx_sent >> 8; answer.data[5] = canix_tx_sent; answer.size = 6; canix_frame_send(&answer); } break; case HCAN_HMS_TX_DROPPED_QUERY : { answer.data[1] = HCAN_HMS_TX_DROPPED_REPLAY; answer.data[2] = canix_tx_dropped >> 24; answer.data[3] = canix_tx_dropped >> 16; answer.data[4] = canix_tx_dropped >> 8; answer.data[5] = canix_tx_dropped; answer.size = 6; canix_frame_send(&answer); } break; case HCAN_HMS_RX_TX_STATS_RESET : { canix_rx_received = 0; canix_rx_lost = 0; canix_tx_sent = 0; canix_tx_dropped = 0; } break; } }
/** multitaster_timer_handler sendet eine Taster UP-/DOWN-Nachricht * auf den CAN-Bus. Der multitaster_timer_handler wird alle 10msec aufgerufen. */ void multitaster_timer_handler(device_data_multitaster *p) { canix_frame message; uint8_t time; // Wenn Taste gedrueckt ist, dann ist der Pin 0, ansonsten 1 uint8_t status = ! tasterport_read(p->config.taster_port); // Message schon mal vorbereiten: message.src = canix_selfaddr(); message.dst = HCAN_MULTICAST_CONTROL; message.proto = HCAN_PROTO_SFP; message.data[0] = HCAN_SRV_HES; // message.data[1] wird unten ausgefuellt message.data[2] = getGroup(p); // message.data[3] wird unten ausgefuellt message.size = 4; if (status) // gedrueckt { // Entprellschutz: if (p->pressed < 255) p->pressed++; } else { // Wenn Schalter-Down schon gesendet wurde, // dann ein Schalter-Up Event senden: if (p->pressed > 3) { //...und kein Rollladentaster im 2-Tasterbetrieb konfiguriert ist: if ( !(p->config.feature & ((1<<FEATURE_MULTITASTER_ROLLADEN_ZU) | (1<<FEATURE_MULTITASTER_ROLLADEN_AUF))) ) { message.data[1] = HCAN_HES_TASTER_UP; message.data[3] = p->config.taster_port; canix_frame_send_with_prio(&message, HCAN_PRIO_HI); } } // Taste wurde losgelassen, also Zaehler zuruecksetzen p->pressed = 0; } if (p->config.feature & (1<<FEATURE_MULTITASTER_ENTPRELL_1S)) time = 100; else time = 3; if (p->pressed == time) // mind. 30msec gedrueckt { if (p->config.feature & (1<<FEATURE_MULTITASTER_ROLLADEN_ZU)) { message.data[1] = HCAN_HES_ROLLADEN_POSITION_SET; message.data[3] = 200; //gewuenschte Rollladenposition: Pos=200=0%=zu } else if (p->config.feature & (1<<FEATURE_MULTITASTER_ROLLADEN_AUF)) { message.data[1] = HCAN_HES_ROLLADEN_POSITION_SET; message.data[3] = 201; //gewuenschte Rollladenposition: Pos=201=100%=auf } else //kein Rollladentaster im 2-Tasterbetrieb { message.data[1] = HCAN_HES_TASTER_DOWN; message.data[3] = p->config.taster_port; } canix_frame_send_with_prio(&message, HCAN_PRIO_HI); } }