Setup Stratum-1 Time Server

พรบ.คอมฯ 50 กำหนดไว้ว่าผู้ให้บริการต้องเก็บข้อมูลจราจรคอมพิวเตอร์ โดยมีความคลาดเคลื่อนของเวลาไม่เกิน 10 msec. จากเวลาอ้างอิง (stratum-0) ซึ่งเป็นเวลาที่ได้จากนาฬิกาอะตอม .. time source ที่เป็นนาฬิกาอะตอมไม่ได้หายากอย่างที่คิด สัญญาณจากดาวเทียม GPS ก็เป็นเวลาที่ได้จากนาฬิกาอะตอมเหมือนกัน ดังนั้นเซ็ต stratum-1 time server ก็แค่ใช้ time source จาก GPS เท่านั้นเอง

เพิ่งได้ USB GPS receiver แบบไม่มียี่ห้อ มาเมื่อหลายวันก่อน ใช้ชิปของ U-Blox ANTARIS LEA-4S ซึ่ง output เป็น NMEA messages ออกมาทาง USB ได้เลย และส่ง 1-Pulse-Per-Second (1PPS) ได้ด้วย เสียบ USB GPS Receiver เข้าคอมพิวเตอร์ (ติดตั้ง เดเบียน ลินุกซ์) ลอง cat /var/log/syslog หรือ dmesg ก็เห็นข้อความประมาณนี้

...
cdc_acm 1-1:1.0: ttyACM0: USB ACM device
usbcore: registered new driver cdc_acm
drivers/usb/class/cdc-acm.c: v0.25:USB Abstract Control Model driver for USB modems and ISDN adapters
...

แปลได้ว่าลินุกซ์เห็น USB GPS receiver เชื่อมกับ USB แล้ว และกำหนด device เป็น /dev/ttyACM0 ลอง

$ lsusb
...
Bus 001 Device 002: ID 1546:01a4 U-Blox AG
...

จะเห็นว่าลินุกซ์รู้จัก U-Blox AG. ด้วย ..ว่าแล้วก็ cat /dev/ttyACM0 ดูเลย

$ cat /dev/ttyACM0
...
$GPRMC,180032.00,A,1628.32246,N,10249.53339,E,0.362,287.84,261208,,,A*62
$GPVTG,287.84,T,,M,0.362,N,0.671,K,A*3B
$GPGGA,180032.00,1628.32246,N,10249.53339,E,1,04,3.23,226.6,M,-27.1,M,,*76
$GPGSA,A,3,22,32,16,06,,,,,,,,,3.98,3.23,2.31*02
$GPGSV,3,1,11,18,04,149,,14,46,058,,22,37,158,42,30,16,038,*71
$GPGSV,3,2,11,32,31,319,20,31,45,353,,29,11,081,,20,08,321,*7C
$GPGSV,3,3,11,16,55,199,44,03,03,197,33,06,10,185,27*4E
$GPGLL,1628.32246,N,10249.53339,E,180032.00,A,A*6C
$GPZDA,180032.00,26,12,2008,00,00*63
$GPRMC,180033.00,A,1628.32249,N,10249.53329,E,0.191,285.38,261208,,,A*66
$GPVTG,285.38,T,,M,0.191,N,0.354,K,A*32
$GPGGA,180033.00,1628.32249,N,10249.53329,E,1,04,3.24,226.6,M,-27.1,M,,*7E
...

จะเห็นเป็น NMEA messages ขึ้นมา .. ข่าวดีคือ NTP อ่าน NMEA message มาเป็น time source ได้เลย .. ก่อนอื่นลง package ntp ก่อน

$ sudo aptitude install ntp

แก้ไฟล์ /etc/ntp.conf เพิ่ม server ที่ใช้ Generic NMEA driver

server 127.127.20.0
fudge 127.127.20.0 time1 0.0 refid GPS

Restart ntp รอสัก 1-2 นาที แล้ว query ดู

$ ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*GPS_NMEA(0)     .GPS.            0 l   13   64  377    0.000   -2.154   3.517

แปลว่า ntp มัน sync กับ stratum-0 time source ได้ และขึ้นมาเป็น stratum-1 NTP server เรียบร้อย :D

อย่างไรก็ตาม หลังรันเซิร์ฟเวอร์และเก็บสถิติไปสักพักก็พบว่า นาฬิกามันไม่ได้แม่นยำอย่างที่คิด เวลาที่ได้มีความคลาดเคลื่อนแกว่งไปมาในช่วง +/- 4 msec บางจังหวะ peak ไปถึง +/- 20 msec ซึ่งถือว่าเป็น stratum-1 server ที่ performance ไม่ได้เรื่องเท่าไหร่ และยังไม่ได้ตามข้อกำหนดตามกฎหมายด้วย .. สาเหตุความคลาดเคลื่อนคงเพราะ NMEA message ไม่ใช่ time source ที่แม่นยำ .. ถ้าจะให้แม่นยำกว่านี้ ต้องใช้ 1PPS

USB GPS receiver ที่ได้มามันไม่ได้ต่อ 1PPS ออกมาให้ใช้งาน จะใช้ก็ต้องต่อเอง .. สิ่งที่ต้องใช้ก็มี DB-9 connector ตัวเมีย สายไฟ หัวแร้งบัดกรี ตะกั่วบัดกรีนิดหน่อย คู่มือของ U-Blox ANTARIS LEA-4S บอกว่าขา 1-PPS (i.e., TIMEPULSE) อยู่ที่ขา 28 จอเข้ากับขา 1 ของ DB-9 (ขา Data Carrier Detect ของ RS-232) และต่อ ground ของ receiver ไปยังขา 5 (GND) ของ DB-9 connector ก่อนเอาไปต่อก็เอา scope วัดสัญญาณดู สัญญาณ 1PPS จะเป็น pulse low-to-high amplitude 3.3 V ใช้ rising edge บอกวินาที

เมื่อต่อเข้ากับ RS-232 ของเครื่อง แล้วทีนี้จะอ่านสัญญาณ 1PPS ยังไงดี ? .. มีอยู่สามทางเลือก LinuxPPS, GPSD, และ SHMPPS

  • LinuxPPS เป็น PPSAPI implementation ตาม RFC2783 มีผลพลอยได้คือ precision ของนาฬิกาจะเป็น nanosecond แต่ต้อง patch / recompile kernel และอาจจะต้อง patch ntpd อีกด้วย (- -‘)
  • GPSD เป็นอีกทางเลือก ลองแล้วไม่สำเร็จ ทั้งที่ GPSD อ่านสัญญาณ 1PPS จาก /dev/ttyS0 แล้ว แต่มันไม่ signal ไปยัง ntpd .. GPS receiver แบบที่ป้อน 1PPS + NMEA ผ่าน RS-232 เพียวๆ อาจจะใช้กับ GPSD ได้
  • SHMPPS เป็นโปรแกรมอ่าน signal จาก serial/parallel port เลือก signal ได้หลายขา แล้วส่งไปยัง ntpd ผ่านทาง SHM (SHare Memory) .. อันนี้ง่ายสุดแล้ว

ก่อนอื่น แก้/เพิ่ม config ใน /etc/ntp.conf ให้ใช้ SHM driver

server 127.127.28.0 minpoll 4 maxpoll 4 prefer
fudge 127.127.28.0 refid PPS

ดาวน์โหลด shmpps extract / make จะได้ shm_splc2 เป็น binary และมี wrapper scripts อีก 2 ตัว ไม่ต้องสนใจ wrapper script ก็ได้ .. ลองสั่งให้ shm_splc2 อ่านสัญญาณ Data Carrier Detect จาก /dev/ttyS0 กันเลย

$ /usr/local/sbin/shm_splc2 -d /dev/ttyS0 -s -l DCD -u 0 -D &

รอสักพัก

$ ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*SHM(0)          .PPS.            0 l    3   16  377    0.000    0.047   0.003
+GPS_NMEA(0)     .GPS.            0 l   13   64  377    0.000   -2.154   3.517

ทิ้งไว้สักพักใหญ่ๆ .. offset และ jitter จะค่อยๆ ลู่เข้าสู่ 0.000

$ ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*SHM(0)          .PPS.            0 l    3   16  377    0.000    0.000   0.001
 GPS_NMEA(0)     .GPS.            0 l   33   64  377    0.000   -5.702  5.288

ปิดท้าย ดูจากกราฟก็จะเห็นว่ามันไม่ได้ 0.000000 s เสียทีเดียว แต่มีจังหวะแกว่งมากบ้างน้อยบ้าง จะเห็นว่านาฬิกามันไม่เที่ยงก็ต้องดู scale usec ซึ่งเทียบกับ stratum-1 servers ของหลายๆ แห่งก็จะได้ precision ประมาณเดียวกัน และน่าจะเกินพอสำหรับ พรบ. ..

เทียบ Offset ของ NMEA กับ 1PPS (scale: msec)

เทียบ Jitter ของ NMEA กับ 1PPS (scale: msec)

Offset ของ 1PPS (scale: usec)

Jitter ของ 1PPS (scale: usec)