├── .github ├── release-drafter.yml └── workflows │ └── release_drafter.yml ├── README.md ├── led_blaster.cpp ├── led_blaster.h ├── notebook_adapter.cpp ├── notebook_adapter.h └── timex-datalink-arduino.ino /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | template: | 2 | ## What’s Changed 3 | 4 | $CHANGES 5 | -------------------------------------------------------------------------------- /.github/workflows/release_drafter.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | release_drafter: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: release-drafter/release-drafter@v5 13 | env: 14 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Timex Datalink Notebook Adapter emulator for Arduino 2 | 3 | This project emulates the [Timex Datalink Notebook Adapter](https://user-images.githubusercontent.com/820984/187855124-5e84451c-f65b-4903-a9eb-f44ddde78eb1.png) for early [Timex Datalink watches](https://en.wikipedia.org/wiki/Timex_Datalink) in Arduino! It is 100% compatible with the original Notebook Adapter, and works with vintage and modern computer hardware. 4 | 5 | This Notebook Adapter emulator is tested to be compatible with: 6 | 7 | - [Timex Data Link® Software 2.1d](https://assets.timex.com/html/data_link_software.html) 8 | - [Timex Ironman Triathlon® Data Link® 2.01](https://assets.timex.com/html/data_link_software.html) 9 | - [Timex BeepwearPRO 1.03](https://assets.timex.com/beepwear) 10 | - [DSI Electronics e-BRAIN v1.1.6](https://archive.org/details/ebrain-1.1.6) 11 | - [timex\_datalink\_client Ruby library](https://github.com/synthead/timex_datalink_client) 12 | 13 | This project is not dependent on any specific Arduino board, although it has been tested to work with these devices: 14 | 15 | - [Teensy LC](https://www.pjrc.com/teensy/teensyLC.html) 16 | - [Raspberry Pi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico) 17 | 18 | These boards have USB serial interfaces and onboard LEDs, so they can be used as-is without any external components: 19 | 20 | ![image](https://user-images.githubusercontent.com/820984/187859185-94f02df7-64f5-4bb3-bf00-12621f5f3b38.png) 21 | 22 | ## How does it work? 23 | 24 | The early Datalink watches receives data over light, and the original intent was to take advantage of [a flashing electron beam on a CRT](https://www.youtube.com/watch?v=GCHHzw4s5W4&t=1168s). Timex also offered a Notebook Adapter accessory intended for mobile users at the time, which replicates the data sent from a CRT using a single LED: 25 | 26 | ![image](https://user-images.githubusercontent.com/820984/203725872-8dc8ec66-57bd-444a-9c36-4138955c83e5.png) 27 | 28 | The Notebook Adapter is a serial device with a proprietary protocol that was reverse-engineered for this project. With the Arduino device present, the original [Timex Datalink software](https://assets.timex.com/html/data_link_software.html) can be configured to use the Notebook Adapter and send data to your watch: 29 | 30 | ![image](https://user-images.githubusercontent.com/820984/203725992-728c8586-0787-4d99-8226-c45812ee6a1b.png) 31 | 32 | ## Using an external LED 33 | 34 | The small onboard LED allows a Timex Datalink 150 watch to sync from a few inches away. With an external LED, it is possible to sync your watch from several feet away. 35 | 36 | An LED can be added tidily to the Teensy LC by soldering an LED cathode (short leg) to the ground pin near the PROG pin, then connecting the anode (long leg) to pin 13 with a resistor, as pictured below. 37 | 38 | ![image](https://user-images.githubusercontent.com/820984/203727953-efcffb19-0522-4573-bdb4-779b6bb5a847.png) 39 | 40 | I discovered that the best performance is obtained by using white LEDs, but every color I tested worked without problems. The LED pictured above is a white 20mA/3-3.2V 14000mcd LED paired with a stiff ¼W 22Ω resistor. 41 | -------------------------------------------------------------------------------- /led_blaster.cpp: -------------------------------------------------------------------------------- 1 | #define LED_PIN LED_BUILTIN 2 | 3 | #define LED_ON_MS_NORMAL 15 4 | #define LED_OFF_MS_NORMAL 450 5 | 6 | #define LED_ON_MS_FAST 6 7 | #define LED_OFF_MS_FAST 408 8 | 9 | #include 10 | 11 | #include "led_blaster.h" 12 | 13 | namespace LedBlaster { 14 | uint16_t led_on_ms; 15 | uint16_t led_off_ms; 16 | 17 | void setup() { 18 | pinMode(LED_PIN, OUTPUT); 19 | enable_fast_mode(false); 20 | } 21 | 22 | void enable_fast_mode(bool fast_mode_enabled) { 23 | if (fast_mode_enabled) { 24 | led_on_ms = LED_ON_MS_FAST; 25 | led_off_ms = LED_OFF_MS_FAST; 26 | } else { 27 | led_on_ms = LED_ON_MS_NORMAL; 28 | led_off_ms = LED_OFF_MS_NORMAL; 29 | } 30 | } 31 | 32 | void emit_0() { 33 | digitalWrite(LED_PIN, HIGH); 34 | delayMicroseconds(led_on_ms); 35 | 36 | digitalWrite(LED_PIN, LOW); 37 | delayMicroseconds(led_off_ms); 38 | } 39 | 40 | void emit_1() { 41 | delayMicroseconds(led_on_ms + led_off_ms); 42 | } 43 | 44 | void emit_byte(uint8_t serial_byte) { 45 | emit_0(); 46 | 47 | for (int i = 0; i < 8; i++) { 48 | bitRead(serial_byte, i) ? emit_1() : emit_0(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /led_blaster.h: -------------------------------------------------------------------------------- 1 | #ifndef LED_BLASTER_H 2 | #define LED_BLASTER_H 3 | 4 | #include 5 | 6 | namespace LedBlaster { 7 | void setup(); 8 | void enable_fast_mode(bool fast_mode_enabled); 9 | void emit_0(); 10 | void emit_1(); 11 | void emit_byte(uint8_t serial_byte); 12 | } 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /notebook_adapter.cpp: -------------------------------------------------------------------------------- 1 | #define COMMAND_QUERY '?' 2 | #define COMMAND_FAST 'V' 3 | #define COMMAND_TRANSMIT 'U' 4 | #define COMMAND_QUERY_PAYLOAD "107\r M764 rev 764100" 5 | 6 | #define DATA_MODE_TIMEOUT_MS 1000 7 | 8 | #include 9 | 10 | #include "led_blaster.h" 11 | #include "notebook_adapter.h" 12 | 13 | namespace NotebookAdapter { 14 | unsigned long last_data_ms = 0; 15 | bool command_mode = true; 16 | 17 | void emulate(uint8_t serial_byte) { 18 | if (millis() - last_data_ms > DATA_MODE_TIMEOUT_MS) { 19 | LedBlaster::enable_fast_mode(false); 20 | command_mode = true; 21 | } 22 | 23 | Serial.write(serial_byte); 24 | 25 | switch(serial_byte) { 26 | case COMMAND_QUERY: 27 | if (command_mode) { 28 | Serial.print(COMMAND_QUERY_PAYLOAD); 29 | Serial.write((byte)0); 30 | } 31 | 32 | break; 33 | case COMMAND_FAST: 34 | if (command_mode) { 35 | LedBlaster::enable_fast_mode(true); 36 | } 37 | 38 | break; 39 | case COMMAND_TRANSMIT: 40 | command_mode = false; 41 | 42 | break; 43 | } 44 | 45 | last_data_ms = millis(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /notebook_adapter.h: -------------------------------------------------------------------------------- 1 | #ifndef NOTEBOOK_ADAPTER_H 2 | #define NOTEBOOK_ADAPTER_H 3 | 4 | #include 5 | 6 | namespace NotebookAdapter { 7 | void emulate(uint8_t serial_byte); 8 | } 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /timex-datalink-arduino.ino: -------------------------------------------------------------------------------- 1 | #include "led_blaster.h" 2 | #include "notebook_adapter.h" 3 | 4 | void setup() { 5 | Serial.begin(9600); 6 | LedBlaster::setup(); 7 | } 8 | 9 | void loop() { 10 | int serial_byte = Serial.read(); 11 | 12 | if (serial_byte != -1) { 13 | NotebookAdapter::emulate(serial_byte); 14 | LedBlaster::emit_byte(serial_byte); 15 | } 16 | } 17 | --------------------------------------------------------------------------------