I. Real-time clock

Click image for larger version

Name:	rtc.gif
Views:	196
Size:	136.4 KB
ID:	1605


Real-time Clock may be a familiar term for many of us. A real-time clock (RTC) is a battery-powered clock that is included in an electrical circuit. Like any other clocks, it keeps track of the current time.

RTCs are present in almost any electronic device which needs to keep accurate time. Nowadays, built-in RTC is a common feature in IoT boards.

In this project, I make the RTC to be displayed and can be synchronized via web browser. For me, that way is much easier to access the RTC than following much more steps via other tools and software.


Web interface

Web interface
II. Things I did:

Hardware components:

1 x PHPoC Blue


PHPoC provides some functions to get RTC data, so that I can retrieve it and display it on a web page. Here I add another local-time clock so we can compare between them.

Note that RTC timing is not always accurate due to its hardware limitation. After all, it is built with modest hardware. For a long period, e.g, over the course of a month, an RTC may have few minutes differed compared to normal-working clocks.

Personally, I think that's okay with a built-in clock. Here, SYNC function is provided so that we can synchronize RTC time with the local time. By this way, we can manually keep the timing deviation as minimum as possible.

Source code includes two files, clock.php and clock_setup.php. clock.php is the main file that is used to retrieve and display RTC clock's data. clock_setup.php is the server side code that handles RTC synchronization request sent from web browser.


Source code


clock.php

PHP Code:
<?php

function rtc_get_date()
{
    
$pid_rtc pid_open("/mmap/rtc0");
    
$date pid_ioctl($pid_rtc"get date");
    
pid_close($pid_rtc);

    
$rtc_time substr($date04) . "-" substr($date42) . "-" substr($date62) . " " substr($date82) . ":" substr($date102) . ":" substr($date122); 
    return 
$rtc_time;
}

?>
<!DOCTYPE html>
<html>
    <head>
        <title>PHPoC Device</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=0.7, maximum-scale=1.0, minimum-scale=0.5, user-scalable=yes">
        <style type="text/css">

            body {
                font-family: verdana, Helvetica, Arial, sans-serif, gulim;
                text-align: center;
                font-size: 18.5px;
                margin: 0;
            }

            table {
                border-collapse: collapse;
                font-size: 15px;
                width: 350px;
                text-align: left;
                margin: 0 auto;
            }

            td {
                padding: 0;
            }

            tr {
                height: 50px;
                color: #898989;
            }

            .header {
                margin: 0 auto;
                position: relative;
                height: 130px;
                color: gray;
            }

            .header a {
                position: relative;
                top: 30px;
                text-decoration: none;
                color: #282828;
            }

            .title {
                font-weight: bold;
                font-size: 24pt;
            }

            .inline {
                display: inline-block;
                margin: 10px 0;
            }

            .nav-line {
                clear: both;
                width: 450px;
                border: 1px solid #efefef;
                position: relative;
                top: 58px;
                margin: 0 auto;
            }

            .theader {
                width: 120px;
                color: #282828;
                padding-left: 20px;
            }

            .btn {
                width: 150px;
                height: 40px;
                border-radius: 25px;
                text-decoration: none;
                line-height: 40px;
                cursor: pointer;
                margin: 0 auto;
                background-color: #898989;
                color: white;
            }

            .btn:hover {
                background-color: #282828;
            }

        </style>
    </head>
    <body onload="init()">
        <div class="header">
            <div class="title"><a href="https://www.phpoc.com/" target="_blank">Built-in Clock</a></div>
        <div class="nav-line"></div>
        </div>
        <form name="phpoc_setup" action="clock_setup.php" method="post">
            <div class="inline">
                <canvas id="rtc_clock"></canvas>
            </div>
            <div class="inline">
                <canvas id="local_clock"></canvas>
                <input type="hidden" name="host_time_txt">
            </div>
            <br>
            <table>
                <tr>
                    <td class="theader">Last updated</td>
                    <td><div id="sync_time"></div></td>
                </tr>
            </table>
            <div class="btn" onclick="time_sync()">SYNC</div>
        </form>
        <br>
    </body>
    <script>

        function get_time(timestamp, is_raw)
        {
            var now;
            if (timestamp != null)
                now = new Date(timestamp);
            else
                now = new Date();

            var year = now.getFullYear();

            var month = now.getMonth() + 1;
            if (month < 10)
                month = "0" + month;

            var day = now.getDate();
            if (day < 10)
                day = "0" + day;

            var h = now.getHours();
            if (h < 10)
                h = "0" + h;

            var m = now.getMinutes();
            if (m < 10)
                m = "0" + m;

            var s = now.getSeconds();
            if (s < 10)
                s = "0" + s;

            if (is_raw)
                return year.toString() + month.toString() + day.toString() + h.toString() + m.toString() + s.toString();

            return year + '-' + month + '-' + day + " " + h + ':' + m + ':' + s;
        }

        function get_current_time(is_raw)
        {
            return get_time(null, is_raw);
        }

        function time_sync()
        {
            var host_time = get_current_time(true);

            phpoc_setup.host_time_txt.value = host_time;
            phpoc_setup.submit();
        }

        function draw_hand(ctx, pos, length, width) {
            ctx.save();
            ctx.beginPath();
            ctx.lineWidth = width;
            ctx.lineCap = "round";
            ctx.rotate(pos);
            ctx.moveTo(0, length / 4);
            ctx.lineTo(0, -length);
            ctx.stroke();
            ctx.rotate(-pos);
            ctx.restore();
        }

        function draw_clock(ctx, timestamp) {
            var radius = ctx.canvas.clientHeight * 0.5;
            var date_time = (timestamp != null) ? new Date(timestamp) : new Date();
            var hour = date_time.getHours();
            var minute = date_time.getMinutes();
            var second = date_time.getSeconds();

            // Draw clock's face
            ctx.clearRect(- radius, - radius, 2 * radius, 2 * radius);
            ctx.beginPath();
            ctx.arc(0, 0, radius * 0.8, 0, 2 * Math.PI);
            ctx.save();
            ctx.fillStyle = '#ffffff';
            ctx.fill();

            ctx.restore();
            ctx.lineWidth = radius * 0.07;
            ctx.stroke();

            // Hour marks
            ctx.lineWidth = radius * 0.02;
            ctx.lineCap = "round";
            ctx.save();
            for (var i = 0; i < 12; i++) {
                ctx.beginPath();
                ctx.rotate(Math.PI / 6);
                ctx.moveTo(radius * 0.74, 0);
                ctx.lineTo(radius * 0.68, 0);
                ctx.stroke();
            }
            ctx.restore();

            // Minute marks
            ctx.save();
            ctx.lineWidth = radius * 0.01;
            for (i = 0; i < 60; i++) {
                if (i % 5!= 0) {
                    ctx.beginPath();
                    ctx.moveTo(radius * 0.74, 0);
                    ctx.lineTo(radius * 0.71, 0);
                    ctx.stroke();
                }
                ctx.rotate(Math.PI / 30);
            }
            ctx.restore();


            // Draw number
            ctx.font = radius * 0.15 + "px arial";
            ctx.textBaseline = "middle";
            ctx.textAlign = "center";

            ctx.save();
            for(var num = 1; num < 13; num++){
                var ang = num * Math.PI / 6;
                ctx.rotate(ang);
                ctx.translate(0, -radius * 0.57);
                ctx.rotate(-ang);
                ctx.fillText(num.toString(), 0, 0);
                ctx.rotate(ang);
                ctx.translate(0, radius * 0.57);
                ctx.rotate(-ang);
            }
            ctx.restore();

            ctx.save();
            ctx.strokeStyle = '#2c3e50';

            // Draw time
            hour = hour % 12;
            hour = (hour * Math.PI / 6) + (minute * Math.PI / (6 * 60)) + (second * Math.PI / (360 * 60));
            draw_hand(ctx, hour, radius * 0.32, radius * 0.03);

            minute = (minute * Math.PI / 30) + (second * Math.PI / (30 * 60));
            draw_hand(ctx, minute, radius * 0.45, radius * 0.02);

            ctx.strokeStyle = '#c0392b';
            second = (second * Math.PI / 30);
            draw_hand(ctx, second, radius * 0.58, radius * 0.01);

            ctx.fillStyle = '#2c3e50';
            ctx.beginPath();
            ctx.arc(0, 0, radius * 0.04, 0, 2 * Math.PI);
            ctx.fill();

            ctx.restore();


            ctx.font = radius * 0.1 + "px arial";
            ctx.fillText(get_time(timestamp), 0, radius * 0.95);
            ctx.fillText(ctx.title, 0, -radius * 0.95);
        }

        function init_clock(id, size, color, title) {
            var canvas = document.getElementById(id);
            canvas.width = size;
            canvas.height = size;
            ctx = canvas.getContext("2d");
            ctx.translate(size * 0.5, size * 0.5);
            ctx.strokeStyle = color;
            ctx.fillStyle = color;
            ctx.title = title;
            return ctx;
        }

        function init() {
            var rtc_time = '<?echo rtc_get_date()?>';
            var cur_time = get_current_time();

            var sync_time_el = document.getElementById('sync_time');

            var offset = new Date().getTimezoneOffset();
            var offset_hrs = parseInt(Math.abs(offset / 60));
            var    offset_min = Math.abs(offset % 60);
            var    timezone;

            if(offset_hrs < 10)
                offset_hrs = '0' + offset_hrs;

            if(offset_min < 10)
                offset_min = '0' + offset_min;

            timezone = ((offset <= 0) ? '+' : '-') + offset_hrs + ':' + offset_min;

            var utc_timestamp = Date.parse(rtc_time.replace(' ', 'T') + timezone);

            sync_time_el.innerText = cur_time;

            var rtc_ctx = init_clock("rtc_clock", 350, '#2980b9', "RTC Time");
            var local_ctx = init_clock("local_clock", 300, '#16a085', "Local Time");

            draw_clock(rtc_ctx, utc_timestamp);
            draw_clock(local_ctx);

            setInterval(function() {
                utc_timestamp += 1000;
                draw_clock(rtc_ctx, utc_timestamp);
                draw_clock(local_ctx);
            }, 1000);
        }

    </script>
</html>

clock_setup.php

PHP Code:
<?php
if(!_SERVER("HTTP_REFERER"))
{
    
header('HTTP/1.1 403 Forbidden');

    
$php_name _SERVER("SCRIPT_NAME");

    echo 
"<html>\r\n",
        
"<head><title>403 Forbidden</title></head>\r\n",
        
"<body>\r\n",
        
"<h1>Forbidden</h1>\r\n",
        
"<p>You don't have permission to access /$php_name on this server.</p>\r\n",
        
"</body></html>\r\n";

    return;
}

function 
rtc_set_date($date)
{
    
$pid_rtc pid_open("/mmap/rtc0");
    
pid_ioctl($pid_rtc"set date $date");
    
pid_close($pid_rtc);
}

$host_time         _POST("host_time_txt");

rtc_set_date($host_time);

?>
<script>
    window.self.location.replace("clock.php");
</script>