From 87d6d957262637b197e5e9ddd54e7d621fd100d5 Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Wed, 27 Mar 2019 19:36:47 +0100 Subject: [PATCH] MOBASERIAL added --- include/mobaserial.h | 16 +++++++ src/mobaserial.cpp | 109 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 include/mobaserial.h create mode 100644 src/mobaserial.cpp diff --git a/include/mobaserial.h b/include/mobaserial.h new file mode 100644 index 00000000..c3b47ab8 --- /dev/null +++ b/include/mobaserial.h @@ -0,0 +1,16 @@ +#ifndef _MOBALINE_H +#define _MOBALINE_H + +#include "globals.h" +#include "dcf77.h" + +#define MOBALINE_FRAME_SIZE (33) +#define MOBALINE_PULSE_LENGTH (100) +#define MOBALINE_HEAD_PULSE_LENGTH (1500) + +void MOBALINE_Pulse(time_t t, uint8_t const *DCFpulse); +uint8_t *IRAM_ATTR MOBALINE_Frame(time_t const t); +void IRAM_ATTR dec2bcd(uint8_t const dec, uint8_t const startpos, + uint8_t const endpos, uint8_t *DCFpulse); + +#endif \ No newline at end of file diff --git a/src/mobaserial.cpp b/src/mobaserial.cpp new file mode 100644 index 00000000..7c330e15 --- /dev/null +++ b/src/mobaserial.cpp @@ -0,0 +1,109 @@ +/* +// Emulate a MOBATIME serial clock controller +// +// Protocol published and described here: +// +// +http://www.elektrorevue.cz/cz/download/time-distribution-within-industry-4-0-platform--controlling-slave-clocks-via-master-clock-hn50/ +*/ + +#ifdef HAS_MOBALINE + +#include "mobaline.h" + +// Local logging tag +static const char TAG[] = __FILE__; + +// triggered by pulse per second to ticker out mobaline frame +void MOBALINE_Pulse(time_t t, uint8_t const *DCFpulse) { + + TickType_t startTime = xTaskGetTickCount(); + uint8_t sec = second(t); + + t = myTZ.toLocal(now()); + ESP_LOGD(TAG, "[%02d:%02d:%02d.%03d] MOBALINE bit %d", hour(t), minute(t), + second(t), millisecond(), sec); + + // induce 3 pulses + for (uint8_t pulse = 0; pulse <= 3; pulse++) { + + switch (pulse) { + + case 0: // start of bit -> start of timeframe for logic signal + if (DCFpulse[sec] != dcf_Z) { + digitalWrite(HAS_DCF77, dcf_high); + vTaskDelay(pdMS_TO_TICKS(MOBALINE_HEAD_PULSE_LENGTH)); + digitalWrite(HAS_DCF77, dcf_high); + vTaskDelay(pdMS_TO_TICKS(MOBALINE_HEAD_PULSE_LENGTH)); + return; // next bit + } else // start the signalling for the next bit + digitalWrite(HAS_DCF77, dcf_high); + break; + + case 1: // 100ms after start of bit -> end of timeframe for logic 0 + if (DCFpulse[sec] == dcf_1) + digitalWrite(HAS_DCF77, dcf_low); + break; + + case 2: // 200ms after start of bit -> end of timeframe for logic 1 + if (DCFpulse[sec] == dcf_0) + digitalWrite(HAS_DCF77, dcf_low); + break; + + case 3: // 300ms after start -> last pulse + break; + + } // switch + + // pulse pause + vTaskDelayUntil(&startTime, pdMS_TO_TICKS(MOBALINE_PULSE_LENGTH)); + + } // for +} // DCF77_Pulse() + +uint8_t *IRAM_ATTR MOBALINE_Frame(time_t const tt) { + + // array of dcf pulses for one minute, secs 0..16 and 20 are never touched, so + // we keep them statically to avoid same recalculation every minute + + static uint8_t DCFpulse[DCF77_FRAME_SIZE + 1]; + + time_t t = myTZ.toLocal(tt); // convert to local time + + // ENCODE HEAD (bit 0)) + DCFpulse[0] = dcf_Z; // not yet implemented + + // ENCODE DAYLIGHTSAVING (bit 1) + DCFpulse[1] = myTZ.locIsDST(t) ? dcf_1 : dcf_0; + + // ENCODE DATE (bits 2..20) + dec2bcd(false, year(t) - 2000, 2, 9, DCFpulse); + dec2bcd(false, month(t), 10, 14, DCFpulse); + dec2bcd(false, day(t), 15, 20, DCFpulse); + + // ENCODE HOUR (bits 21..26) + dec2bcd2(false, hour(t), 21, 26, DCFpulse); + + // ENCODE MINUTE (bits 27..33) + dec2bcd2(false, minute(t), 27, 33, DCFpulse); + + // timestamp this frame with it's minute + DCFpulse[34] = minute(t); + + return DCFpulse; + +} // MOBALINE_Frame() + +// helper function to convert decimal to bcd digit msb +void IRAM_ATTR dec2bcd(uint8_t const dec, uint8_t const startpos, + uint8_t const endpos, uint8_t *DCFpulse) { + + uint8_t data = (dec < 10) ? dec : ((dec / 10) << 4) + (dec % 10); + + for (uint8_t i = endpos; i >= startpos; i--) { + DCFpulse[i] = (data & 1) ? dcf_1 : dcf_0; + data >>= 1; + } +} + +#endif // HAS_MOBALINE \ No newline at end of file