Coder Social home page Coder Social logo

txtempus's Introduction

Radio time station transmitter using the Raspberry Pi and Nvidia Jetson

I am living in a country where there is no DCF77 sender nearby for my European radio controlled wristwatch to get its time. This vintage Junghans Mega doesn't have any buttons to set the time, so to bring it back to life, I built my own 'transmitter', taking the NTP time of a Raspberry Pi and generating a modulated signal via GPIO pins to then magnetically couple it into the watch ferrite.

Since many other long-wave time stations around the world use similar concepts of sending amplitude modulated time, other time services have been added.

This program is useful if you have a clock that otherwise does not get any reception. This magnetical coupling is very low power and only works over a few centimeters, but before running this program, make sure you follow your local laws with regard to restrictions on radio transmissions.

Platform

txtempus supports Raspberry Pi series and Nvidia Jetson Series (experimental).

Raspberry Pi

So far, it has been tested on a Pi3 and a Pi Zero W. There has been a report of different frequencies generated with an older Pi (Bug #1), so until we have a definitive list of available clock sources inside these, check out that bug for a workaround.

Nvidia Jetson Series (experimental)

So far, it has been tested only on a Jetson Nano, but all Jetson devices except for TX1 and TX2 (there is no available pwm pin) are supported.

Supported Time Services

DCF77

The DCF77 (Germany) signal is a 77.5kHz carrier, that is amplitude modulated with attenuations every second of the minute except the 59th to synchronize. The length of the attenuation (100ms and 200ms) denotes bit values 0 and 1 respectively so in each minute, 59 bits can be transferred, containing date and time information.

The Raspberry Pi has ways to create frequencies by integer division and fractional jitter around that, which allows us to generate a frequency of 77500.003Hz, which is close enough. Can be chosen with -s DCF77 option.

WWVB

The WWVB (USA) is on a 60kHz carrier, and also transmits one bit per second with different attenuation times (200ms zero, 500ms one; 800ms sync) and multiple synchronization bits. Use -s WWVB option for this one.

MSF

The MSF (United Kingdom) has yet another encoding, transferring two bits per second. Carrier is 60kHz. Option is -s MSF.

JJY

The JJY (Japan) is similar to WWVB, with same timings of carrier switches, but reversed power levels. Some bits are different. Two senders exist in Japan with 40kHz and 60kHz carrier; their simulations can be chosen with command line options -s JJY40 and -s JJY60. If you're in/or want to display a different time-zone, issue #17 might be of interest to you.

Minimal External Hardware

Raspberry Pi

The external hardware is simple: we use the frequency output on one pin and another pin to pull the signal to a lower level for the regular attenuation.

To operate, you need three resistors: 2x4.7kΩ and one 560Ω (precision not critical), wired to GPIO4 and GPIO17 like so:

Schematic Real world

GPIO4 and 17 are on the inner row of the Header pin, three pins inwards on the Raspberry Pi GPIO-Header.

You don't need GPIO17 and the 560Ω resistor for MSF, as that works with switching the signal (on-off keying) instead of attenuating. In that case, you can replace the sequence of two 4.7kΩ resistors with a single 10kΩ.

Now, wire a loop of wire between the open end of the one 4.7kΩ and ground - this loop acts as coupling coil to the watch ferrite antenna. The signal is very weak, so bring this wire-loop close to your radio watch/clock.

In the following image, which was the first experiment, it is wrapped around the antenna, but it is not strictly needed: anything within a few centimeters should work.

Being too close to the clock can confuse a sensitive receiver, so you might need to experiment with the distance. If your clock/watch is not receiving, add more turns to your transmission coil. In the picture at the bottom of the page you see that I am using about 10-20 turns on the coil (reddish oval lying on the Pi).

This set-up should work for most watches if you have them in close vicinity.

The antenna set-up is intentionally not optimal to just be good enough for a local watch but hopefully not causing interference. Further improvements of course can be done to the antenna for increased transmission distance, such as using a ferrite, making it an LC circuit or adding an amplifier. Only go in this direction after familiarizing yourself with allowances of radio transmissions in your area on your frequency of interest.

Nvidia Jetson Series (experimental)

(*Please read the external hardware for the Raspberry Pi above first.) On Jetson, the external hardware setup is slightly different from the Raspberry Pi.

We need one "PWM Pin" for a frequency output, and one "Attenuation Pin" for modulating the signal. These pins vary by the Jetson model. Please check the following table.

Devices PWM pin (Board numbering) Attenuation pin (Board numbering)
Jetson TX1, Jetson TX2 Not supported Not supported
Jetson Xavier, Clara AGX Xavier, Jetson Orin 18 16
Other devices 33 35

To operate, you need three resistors: 2x4.7kΩ and one 560Ω (precision not critical) and one NPN transistor (nearly any NPN transistor should work. I'm using KTC3198).

Here's the full schematic of the external hardware for the Jetson Series:

Schematic Real world (Jetson Nano)

Like the Raspberry Pi, you don't need the Attenuation Pin and the 560Ω resistor for MSF, and a wire-loop between the 4.7kΩ register and the ground acts as coupling coil. Bring this wire-loop close to your radio watch/clock.

Build

 sudo apt-get install git build-essential cmake -y
 git clone https://github.com/hzeller/txtempus.git
 cd txtempus
 mkdir build && cd build

Rapberry Pi

 cmake ../ # or cmake ../ -DPLATFORM=rpi
 make

Nvidia Jetson Series (experimental)

Before you build txtempus on your Jetson:

  • You should install JetsonGPIO which is a library that enables the use of Jetson's GPIOs.
  • The system pinmux must be configured to connect the hardware PWM controlller(s) to the relevant pins. Read the L4T documentation for details on how to configure the pinmux.
 cmake ../ -DPLATFORM=jetson
 make

Transmit!

 sudo ./txtempus -v -s DCF77

With -s, you set the type of time signal you want to transmit.

There are a few options you can set. The -r option is useful to have the program run only for the few minutes it might take for a clock to synchronize.

By default, the current system time is transmitted. The -t option allows different times for testing.

usage: ./txtempus [options]
Options:
        -s <service>          : Service; one of 'DCF77', 'WWVB', 'JJY40', 'JJY60', 'MSF'
        -r <minutes>          : Run for limited number of minutes. (default: no limit)
        -t 'YYYY-MM-DD HH:MM' : Transmit the given local time (default: now)
        -z <minutes>          : Transmit the time offset from local (default: 0 minutes)
        -v                    : Verbose.
        -n                    : Dryrun, only showing modulation envelope.
        -h                    : This help.

Don't connect monitor (Raspberry Pi)

Don't connect a monitor to the Pi, just operate it headless.

The internal oscillator used is also used for HDMI in the Rasbperry Pi; it will be changing its frequency if a monitor is connected and the transmission will fail. There should probably be a flag added to generate the frequency from an alternative oscillator instead; but until that is implemented, just don't connect a monitor and it will work. See the very wrong frequency bug for details.

Action video - watch a watch synchronize

In the video below, you can see how a watch is set with this set-up. After it is manually reset, it waits until it sees the end-of-minute mark (which does not have any amplitude modulation) and then starts to count on from second 59, then gathering the data that is following.

An interesting observation: you see that the watch already gets into fully set mode after about 50 seconds, even though there is the year data after that. This particular watch never shows the year, so it just ignores that.

Showing the modulation envelope

Mostly for understanding the protocol, the -n option allows to observe how the amplitude modulation of each second looks like. Unlike the regular transmission, don't need to be root or run on the Raspberry Pi to use this option. Underscores (_) show low power carrier, hashes (#) high power:

$ ./txtempus -n -s wwvb
2018-08-17 13:22:00 -> tx-modulation
:00 [________##]
:01 [__########]
:02 [_____#####]
:03 [__########]
:04 [__########]
:05 [__########]
:06 [__########]
:07 [_____#####]
:08 [__########]
:09 [________##]
:10 [__########]
:11 [__########]
  ... and so on for the whole minute ...

Limitations

In some of these protocols, there are additional bits that contain information about upcoming daylight saving times, leap seconds or difference to astronomic time. These are currently not set, but usually clocks are fine with it.

Some time stations also phase-modulate their carrier, txtempus does not.

The frequency generation does not seem to work on a Raspberry Pi4. Please use older Pis for now until that is figured out (also pull requests accepted if you know details).

Installation

Software

After building, you can install the binary in some standard location

 sudo make install

Watch holder

Each set-up will be different. In my case, I need my DCF77 radio watch getting set over night. So I built this watch holder that presents the watch upright while the antenna (in the wristband) is close to the 'transmission coil' that is lying flat on the Pi. The bottom of the 3D printed case is filled with lead shot in epoxy to provide a stable base.

The Raspberry Pi Zero W runs ntpd, PLL locking the system time to various stratum 1 NTP servers keeping it at atomic time within ±50ms. This particular watch only checks the radio twice a day at 2am and 3am, so there is a cron-job that runs txtempus around these times for a few minutes.

Crontab

If you put the following line in your /etc/crontab txtempus will be started at 1:57 and 2:57 at night and runs for 10 minutes.

57 1,2    * * *   root    /usr/bin/txtempus -s DCF77 -r 10

(this requires that you have installed txtempus so that it can be found in /usr/bin : sudo make install).

watch holder ... with watch

tx common telecommunication abbreviation for 'transmit'
tempus, n Latin. Time; period; age

txtempus's People

Contributors

hzeller avatar icb- avatar pjueon avatar sakhnik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

txtempus's Issues

Very wrong frequency generated (1.6kHz instead of 60kHz)

Hello H,

Many thanks for this project. I was looking for exactly this for my Casio watch since I moved countries.
It built fine and appears to run but generates very low frequencies on my RPi model B+ v1.2. I'm not 100% sure what Pi you are using so it could well be you have a different model.

Using './txtempus -s MSF' insead of 60kHz, my 'scope shows only 1.611kHz and of course no devices work. Same with WWVB option. Trying the DCF77 produces 2.081kHz instead of 77.5kHz.

Would you have any ideas?

'guv.

Amplifier

Hello!
How to make a signal amplifier? 3-5 meters for Meteostation RST 88777

does not compile in Visual Studio Cross env for RPI

Hi,
I wanted to compile it in VS2019, but it doesn't. I works fine, when directly compiled on RPI 3B. VS creates an endless Error list for the system include stl_function.h complaining about "auto"

Schweregrad Code Beschreibung Projekt Datei Zeile Unterdrückungszustand Fehler (aktiv) E0040 Es wurde ein Bezeichner erwartet. DCF77 C:\Users\hk\AppData\Local\Microsoft\Linux\HeaderCache\1.0\-460273873\usr\include\c++\10\bits\stl_function.h 537 Fehler (aktiv) E1598 "auto" ist an dieser Stelle nicht zulässig. DCF77 C:\Users\hk\AppData\Local\Microsoft\Linux\HeaderCache\1.0\-460273873\usr\include\c++\10\bits\stl_function.h 537 Fehler (aktiv) E0065 Es wurde ein ";" erwartet. DCF77 C:\Users\hk\AppData\Local\Microsoft\Linux\HeaderCache\1.0\-460273873\usr\include\c++\10\bits\stl_function.h 538 Fehler (aktiv) E0840 In einer Deklaration einer primären Vorlage ist keine Vorlagenargumentliste zulässig. DCF77 C:\Users\hk\AppData\Local\Microsoft\Linux\HeaderCache\1.0\-460273873\usr\include\c++\10\bits\stl_function.h 556
` private:
template <typename _Tp, typename _Up>
static constexpr decltype(auto)
_S_cmp(_Tp&& __t, _Up&& __u, false_type)
{ return std::forward<_Tp>(__t) > std::forward<_Up>(__u); }

  template <typename _Tp, typename _Up>
static constexpr bool
_S_cmp(_Tp&& __t, _Up&& __u, true_type) noexcept
{
  return greater<const volatile void*>{}(
      static_cast<const volatile void*>(std::forward<_Tp>(__t)),
      static_cast<const volatile void*>(std::forward<_Up>(__u)));
}

  // True if there is no viable operator> member function.
  template<typename _Tp, typename _Up, typename = void>
struct __not_overloaded2 : true_type { };

  // False if we can call T.operator>(U)
  template<typename _Tp, typename _Up>
struct __not_overloaded2<_Tp, _Up, __void_t<
  decltype(std::declval<_Tp>().operator>(std::declval<_Up>()))>>`

It may have something to do w/ the following:
https://stackoverflow.com/questions/40368535/unable-to-get-type-of-function-returning-constexpr-auto
but this beyond my CPP knowledge. Could you make your code compatible?
BR
hk

Crontab instruction

I have successfully used the JJY60 service on pi zero to sync a citizen watch from japan which can’t receive any other service. I used the transistor circuit by Andreas Spiess with a ferrite 60hz receiver aerial as the transmitter. However, I cannot figure out how to set up Txtempus in crontab to schedule it to run. Please could somebody share the commands required to do this within crontab?

Ps thanks for sharing txtempus!

Implementing txtempus for NVIDIA Jetson series

Thanks for the great application!
Personally, I don't have any raspberry PI device. But I have NVIDIA Jetson Nano instead.
So I'm implementing this project for NVIDIA Jetson series by using my library.

I think it would be cool if the users can choose the platform when you build the txtempus.
For example:

cmake -DPLATFORM=jetson  # default value: rpi

The main logics and the interface can be reused, so you can easily add support for other platforms in the future
by only implementing the hardware control part.

Actually I almost finished implementing it,
and it works perfectly with Jetson Nano and my watch which uses JJY signal.

So, here's my question:
Can I make a pull request about this?

If you think it would make the project too complicated and you don't want it,
I will make a separate repository for NVIDIA Jetson series (txtempus-jetson or something like that).

Rpi2 60khZ frequency needs overclock

Hello,

Thank you very much for this program. It is great.
I used it on my Rpi2 for WWVB/Marathon Clock and did not work (on 60kHz) until I overclocked it to 1GHz. After this fix it works perfectly on 60 and 77.5 kHz but not on 40 kHz.
Also my RPi2 does not have X installed and the transmitter work perfectly with the HDMI connected; perhaps problems are when X is in use. Keep up the good work.

Best Regards

Problem With Non Raspberry OS

My Raspberry Pi 3 on Debian 12 is giving me the following errors when txtempus is run.

non-existent Revision: Could not determine Pi model
mmap error: : Operation not permitted
MMapping from base 0x3f000000, offset 0x200000
Need to be root

All of this is conjecture on my part as I am not a programmer, but after poking around the code, it appears that the programming is using /proc/cpuinfo to determine the needed information on model etc. Unfortunately it also appears that the /proc/cpuinfo information provided by the Raspberry Pi OS is non standard (at least it doesn’t match the Debain or Slackware versions) and gives more information than was intended. Is it possible for the code to query the needed information from the user when needed, so it can be used on all Raspberry Pis regardless of the OS?

JJY not working

Hi!

Tested the code on my brothers watch from Japan and it didn't detected any signal.
Measured the output with my spectrum analyser and the frequency is correct.
With help of the debug output I found that ones and zeros was switched. So I adjusted the code in jjy-source.cc with: return {{CarrierPower::HIGH, bit ? 500 : 800}, {CarrierPower::LOW, 0}};.
Now the watch is detecting the signal with full signal meter, but something is still wrong and the time update times out...

/// Marcus

Copy

Is there any possibility that a copy of this could be made, for someone that has a radio controlled Citizen, and shipped to, say for instance, Norway?

License?

It would be much appreciated if this is open sourced with MIT/BSD - it's up to the author. :)

Use different GPIO pins

Hello there!

Firstly, thank you for making this and taking the time to document it and publish it. I easily got it working, even though I didn't have components and ruminated about the resistors. I just ended up trying a handy 10k potentiometer (set at 50%) and just sending the middle leg directly to GPIO17 (not my main question, but how bad an idea was that?)

Wondering though if it would be possible to use some other GPIO pin other than 4 for modulation?

I naively tried to change the value in GPIO::EnableClockOutput from 4 to 27 and moved that wire from pin 7 to pin 13, but that did not seem to work. Should it have? Is there something special about GPIO4 or are there other places that need to be tweaked other than just this section of code?

For context, I have a Pi with a GPS hat that I am using as my NTP server on my network. The hat uses GPIO4 for it's PPS signal to the Pi, so if I could move the modulation off of GPIO4, then this Pi could serve both purposes.

Thanks again,
Bob.

Tried to sync a weather station without success - Help Wanted

Hello!
I tried to sync a DCF77 weather station without success. I have a raspberry model B and this what I get when I execute txtempus. I attached txmodulation file and hardware setup image.

sudo txtempus -v  -s DCF77
Requesting 77500 Hz, getting 77500.003 Hz carrier
2019-05-31 19:36:59
2019-05-31 19:37:59
2019-05-31 19:38:59
2019-05-31 19:39:44

How can I know if it is doing something?
DCF77_Hardware
TXModulation.txt

[Suggestion] Removal of attenuation pin

I use txtempus with a Raspberry Pi Model B and an amplifier like the one described in issue #8, with an AM receiver antenna . My radio controlled watch is a Casio G-Shock GW-5500-1.

While playing with a fictitious time envelope (created by txtempus) and an Arduino, I notice that it doesn't seem mandatory to attenuate the carrier for any of the time services. One could simply switch it off as with MSF.

This configuration has some advantages :

  • slight simplification of txtempus code
  • simplification of external hardware (see below)
  • more amplitude between high and low should improve the clarity of the signal in noisy environments (intuitive guesswork not based on actual measurements).

This change could be easily tested in txtempus : simply replace LOW by OFF in GetModulationForSecond function in dcf77-source.cc, jjy-source.cc and wwvb-source.cc.

The hardware described in issue #8 could still be used as is. GPIO17 is no longer used so R2 can be removed.

For more simplification T1 could be replaced by a N mosfet with gate directly connected to GPIO4. You'll then have this 3 components circuit :

MOSFET_OSCILLATOR_JJY40 EMF

DSC_4398s
The hairy 3 components circuit

As small mosfets like BS270 can handle up to 250 mA, you can design a more powerful emitter with two complementary mosfets as a NOT gate and a lower value resistor :

DUAL-MOSFET_OSCILLATOR_JJY40s

I successfully tested these circuits with JJY40 et DCF77 signals and reached a range of ten meters with JJY40 and the dual mosfet configuration.

DSC_4399s
G-Shock strong reception (L3)

JJY Testing Feedback

Thanks for txtempus! I'm very happy this exists and this was a fun project to practice my crappy soldering skills.

I can confirm JJY works with one of my watches! However, I found something interesting worth sharing. Not sure if this has to do with the code, the JJY signal, or the hardware of the watch.

Background on my watch

The watch I'm using is a Citizen PMD56-2951 (H100 movement). The way this watch works, and I'm not sure if this is the same for all other JJY-capable watches, is it orients to JST.

Instead of setting a UTC offset like most radio controlled watches, a user of this particular watch needs to set a JST offset. What that means is that if I'm on the Pacific timezone, I don't set this watch to -8. I have to set the appropriate offset to JST which is -16 or -17 hours depending on Daylight Savings or Standard. At the moment the watch is set to -16 to JST.

Using txtempus with this watch

So when I run the code without options other than choosing JJY40 or JJY60, it sets my time 16 hours behind my timezone (i.e., 16 hours behind Pacific). In order for it to sync correctly to my watch, I have to set -z 960 (adding 16 hours) for it to give me what I need.

The other option is to set the watch's offset to 0 and not pass any value to -z.

I just wanted to share this in case the Citizen H100 community is experiencing some weirdness.

WWVB daylight davings time

It works to simulate WWVB to set a Five Senses talking watch, thanks!

But it does not appear to handle daylight savings time in the US.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.