dcf77.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. #include "dcf77.h"
  2. #define DST_BIT 17
  3. #define MIN_BIT 21
  4. #define HOUR_BIT 29
  5. #define DAY_BIT 36
  6. #define WEEKDAY_BIT 42
  7. #define MONTH_BIT 45
  8. #define YEAR_BIT 50
  9. // The signal will contain the time of when the signal ends
  10. // Bits: 1-bit is signal, 2-bit is prepend dash for visual output and 4-bit is mark as "X" in visual output
  11. static uint8_t dcf77_bits[] = {
  12. 0, // 00: Start of minute (Always 0)
  13. 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 01: Weather broadcast / Civil warning bits
  14. 2, // 15: Call bit: abnormal transmitter operation
  15. 0, // 16: Summer time announcement. Set during hour before change
  16. 0, 1, // 17: 01=CET, 10=CEST
  17. 0, // 19: Leap second announcement. Set during hour before leap second
  18. 1, // 20: Start of encoded time (always 1)
  19. 2, 0, 0, 0, 0, 0, 0, 0, // 21: Minutes (7bit + even parity, 00-59)
  20. 2, 0, 0, 0, 0, 0, 0, // 29: Hours (6bit + even parity, 0-23)
  21. 2, 0, 0, 0, 0, 0, // 36: Day of month (6bit, 1-31)
  22. 2, 0, 0, // 42: Day of week (3bit, 1-7, Monday=1)
  23. 2, 0, 0, 0, 0, // 45: Month number (5bit, 1-12)
  24. 2, 0, 0, 0, 0, 0, 0, 0, 0, // 50: Year within century (8bit + even parity for 36-58, 00-99)
  25. 6 // 59: Minute mark
  26. };
  27. /**
  28. * Encode a value into a part of a dcf77 signal
  29. * @param start Index where the encoded value should start in the sinal bits array
  30. * @param len Number of bits in the encoded value
  31. * @param val The value to be encoded
  32. * @param par The parity flag (0 top disable parity, 1 for even parity bit to be appended to the encoded value, -1 for even parity bit to be appended to the encoded value but being based on the value currently in the first position in the signal bits (overflow from before))
  33. */
  34. void dcf77_encode(int start, int len, int val, int par) {
  35. // Set parity init bit
  36. uint8_t parity = 0;
  37. if(par == -1) {
  38. // Use first bit as parity init
  39. parity = dcf77_bits[start] & 1;
  40. }
  41. // Parse value into bits (little endian)
  42. uint8_t byte = ((val / 10) << 4) + (val % 10);
  43. // Go through byte from right (low) to left (high)
  44. for(int bit = 0; bit < len; bit++) {
  45. // Get bit
  46. uint8_t dcf77_bit = (byte >> bit) & 1;
  47. // XOR onto parity
  48. parity ^= dcf77_bit;
  49. // Set bit in signal bits (keep flags for visual output)
  50. dcf77_bits[start + bit] = (dcf77_bits[start + bit] & 0x6) + dcf77_bit;
  51. }
  52. // Append parity bit if parity bit is enabled (keep flags for visual output)
  53. if(par != 0) {
  54. dcf77_bits[start + len] = (dcf77_bits[start + len] & 0x6) + (parity & 1);
  55. }
  56. }
  57. void set_dcf77_time(DateTime* datetime, bool is_dst) {
  58. dcf77_encode(DST_BIT, 2, is_dst > 0 ? 0b01 : 0b10, 0); // Disable parity
  59. dcf77_encode(MIN_BIT, 7, datetime->minute, 1);
  60. dcf77_encode(HOUR_BIT, 6, datetime->hour, 1);
  61. dcf77_encode(DAY_BIT, 6, datetime->day, 1);
  62. dcf77_encode(WEEKDAY_BIT, 3, datetime->weekday, -1); // Use first bit as parity init
  63. dcf77_encode(MONTH_BIT, 5, datetime->month, -1); // Use first bit as parity init
  64. dcf77_encode(YEAR_BIT, 8, datetime->year % 100, -1); // Use first bit as parity init
  65. }
  66. bool get_dcf77_bit(int sec) {
  67. // Return the bit for the second
  68. return dcf77_bits[sec % 60] & 1;
  69. }
  70. char* get_dcf77_data(int sec) {
  71. // Array for data to be displayed
  72. static char data[70];
  73. // Index
  74. int idx = 0;
  75. // Optimization: Only 25 charcters can be displayed -> don't calculate any more
  76. int start = sec > 25 ? sec - 25 : 0;
  77. for(int bit = start; bit <= sec; bit++) {
  78. // Prepend a dash if 2-bit is set
  79. if(dcf77_bits[bit] >> 1 & 1) {
  80. data[idx++] = '-';
  81. }
  82. // Only set data is not displayed as "X"
  83. if(dcf77_bits[bit] >> 2 & 1) {
  84. data[idx++] = 'X';
  85. } else {
  86. // Set data to last bit (ascii id of 0 plus 0 or 1)
  87. data[idx++] = '0' + (dcf77_bits[bit] & 1);
  88. }
  89. }
  90. // Terminate string wit null byte and return
  91. data[idx] = 0;
  92. return data;
  93. }