{"action":"created","comment":{"url":"https://api.github.com/repos/mbedmicro/mbed/pulls/comments/25871768","id":25871768,"diff_hunk":"@@ -39,71 +171,113 @@ uint32_t us_ticker_read()\n         us_ticker_init();\n     }\n \n-    uint64_t value;\n-    app_timer_cnt_get(&value); /* This returns the RTC counter (which is fed by the 32khz crystal clock source) */\n-    return ((value * 1000000) / (uint32_t)APP_TIMER_CLOCK_FREQ); /* Return a pseudo microsecond counter value.\n-                                                                  * This is only as precise as the 32khz low-freq\n-                                                                  * clock source, but could be adequate.*/\n-}\n-\n-/* An adaptor to interface us_ticker_irq_handler with the app_timer callback.\n- * Needed because the irq_handler() doesn't take any parameter.*/\n-static void us_ticker_app_timer_callback(void *context)\n-{\n-    us_ticker_appTimerRunning = false;\n-    us_ticker_irq_handler();\n+    /* Return a pseudo microsecond counter value. This is only as precise as the\n+     * 32khz low-freq clock source, but could be adequate.*/\n+    return RTC_UNITS_TO_MICROSECONDS(rtc1_getCounter());\n }\n \n+/**\n+ * Setup the us_ticker callback interrupt to go at the given timestamp.\n+ *\n+ * @Note: Only one callback is pending at any time.\n+ *\n+ * @Note: If a callback is pending, and this function is called again, the new\n+ * callback-time overrides the existing callback setting. It is the caller's\n+ * responsibility to ensure that this function is called to setup a callback for\n+ * the earliest timeout.\n+ *\n+ * @Note: If this function is used to setup an interrupt which is immediately\n+ * pending--such as for 'now' or a time in the past,--then the callback is\n+ * invoked a few ticks later.\n+ *\n+ * @suggestion: Avoid studying this code unless you're forced to. And please\n+ * don't prove me wrong--I've spent too much time trying to get this code to\n+ * behave correctly; currently it pretends to do so, and I don't want to learn\n+ * anything different unless I'm given an easy way to reproduce the problem.\n+ */\n void us_ticker_set_interrupt(timestamp_t timestamp)\n {\n     if (!us_ticker_inited) {\n         us_ticker_init();\n     }\n \n-    if (us_ticker_appTimerID == TIMER_NULL) {\n-        if (app_timer_create(&us_ticker_appTimerID, APP_TIMER_MODE_SINGLE_SHOT, us_ticker_app_timer_callback) != NRF_SUCCESS) {\n-            /* placeholder to do something to recover from error */\n-            return;\n-        }\n+    /*\n+     * Alert: Get yourself a beverage.\n+     *\n+     * In comes a harmless, merry-looking 32-bit timestamp in units of micro-\n+     * seconds from the generic us_ticker_api. On most platforms with 32-bit\n+     * hardware timers running at micro-second precision this poses no serious\n+     * challenge. But on the nRF51, we use an RTC timer running at 32kHz to\n+     * implement a low-power us-ticker. This brings with a problem that's rooted\n+     * in the fact that 1000000 is not a multiple of 32768.\n+     *\n+     * Going from a micro-second based timestamp to a 32kHz based RTC-time is a\n+     * linear mapping; but then when the 32-bit micro-second timestamp wraps\n+     * around, unfortunately the underlying RTC counter doesn't. The result is\n+     * that timestamp expiry checks on micro-second timestamps don't yield the\n+     * same result when applied on the corresponding RTC timestamp values.\n+     * You'll really need to whip up some numbers to see the problem.\n+     *\n+     * As far as I understand--and this could just be me turning old and rusty,\n+     * --there is no clean solution for this problem at the wrap-around\n+     * boundary. I'd be interested to be shown how. My solution is to translate\n+     * the incoming 32-bit timestamp into a virtual 64-bit timestamp based on\n+     * the knowledge of system-uptime, and then use this 64-bit value to do a\n+     * linear mapping to RTC time. 64-bit timestamp values shouldn't wrap around\n+     * in a few thousand years. This may be pulling down the theoretical upper\n+     * boundary for the shelf life of nRF products when used with mbed; please\n+     * accept my two to the power 56 apologies for that. But then life often\n+     * forces one to live within constraints. What's the meaning of all this\n+     * anyway?\n+     *\n+     * System uptime on an nRF is maintained using RTC's counter. We track the\n+     * overflow count to extend the 24-bit hardware counter by an additional 32\n+     * bits. This then forms the basis for system time.\n+     * RTC_UNITS_TO_MICROSECONDS() converts this into microsecond units (in\n+     * 64-bits). We then shave off the lower 32-bits of it and add in the\n+     * incoming timestamp to get a mapping into a virtual 64-bit timestamp.\n+     * There's one additional check to handle the case of wraparound for the\n+     * 32-bit timestamp.\n+     */\n+    uint64_t timestamp64 = (RTC_UNITS_TO_MICROSECONDS(rtc1_getCounter()) & ~(uint64_t)0xFFFFFFFF) + timestamp;\n+    if ((us_ticker_read() > 0xF0000000) && (timestamp < 0x10000000)) {","path":"libraries/mbed/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/us_ticker.c","position":246,"original_position":246,"commit_id":"e01cb0ae84b8c1cefa1cac3a637147ac9bc2ee43","original_commit_id":"e01cb0ae84b8c1cefa1cac3a637147ac9bc2ee43","user":{"login":"rgrover","id":112704,"avatar_url":"https://avatars.githubusercontent.com/u/112704?v=3","gravatar_id":"","url":"https://api.github.com/users/rgrover","html_url":"https://github.com/rgrover","followers_url":"https://api.github.com/users/rgrover/followers","following_url":"https://api.github.com/users/rgrover/following{/other_user}","gists_url":"https://api.github.com/users/rgrover/gists{/gist_id}","starred_url":"https://api.github.com/users/rgrover/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rgrover/subscriptions","organizations_url":"https://api.github.com/users/rgrover/orgs","repos_url":"https://api.github.com/users/rgrover/repos","events_url":"https://api.github.com/users/rgrover/events{/privacy}","received_events_url":"https://api.github.com/users/rgrover/received_events","type":"User","site_admin":false},"body":"you're correct. I'm duplicating work here. I could reuse the value from RTC_UNITS_TO_MICROSECONDS(rtc1_getCounter()) instead of calling us_ticker_read(). thanks.","created_at":"2015-03-05T15:32:24Z","updated_at":"2015-03-05T15:32:24Z","html_url":"https://github.com/mbedmicro/mbed/pull/932#discussion_r25871768","pull_request_url":"https://api.github.com/repos/mbedmicro/mbed/pulls/932","_links":{"self":{"href":"https://api.github.com/repos/mbedmicro/mbed/pulls/comments/25871768"},"html":{"href":"https://github.com/mbedmicro/mbed/pull/932#discussion_r25871768"},"pull_request":{"href":"https://api.github.com/repos/mbedmicro/mbed/pulls/932"}}},"pull_request":{"url":"https://api.github.com/repos/mbedmicro/mbed/pulls/932","id":30027848,"html_url":"https://github.com/mbedmicro/mbed/pull/932","diff_url":"https://github.com/mbedmicro/mbed/pull/932.diff","patch_url":"https://github.com/mbedmicro/mbed/pull/932.patch","issue_url":"https://api.github.com/repos/mbedmicro/mbed/issues/932","number":932,"state":"open","locked":false,"title":"Replace Nordic's appTimer with a driver for RTC1","user":{"login":"rgrover","id":112704,"avatar_url":"https://avatars.githubusercontent.com/u/112704?v=3","gravatar_id":"","url":"https://api.github.com/users/rgrover","html_url":"https://github.com/rgrover","followers_url":"https://api.github.com/users/rgrover/followers","following_url":"https://api.github.com/users/rgrover/following{/other_user}","gists_url":"https://api.github.com/users/rgrover/gists{/gist_id}","starred_url":"https://api.github.com/users/rgrover/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rgrover/subscriptions","organizations_url":"https://api.github.com/users/rgrover/orgs","repos_url":"https://api.github.com/users/rgrover/repos","events_url":"https://api.github.com/users/rgrover/events{/privacy}","received_events_url":"https://api.github.com/users/rgrover/received_events","type":"User","site_admin":false},"body":"This requires careful review and testing. I've done a fair bit, but much more is needed.\r\nThis has been very tricky code owing mostly to:\r\n\r\n* trickiness involved in manipulating lists from re-entrant functions in interrupt context.\r\n* RTC counter being 24bit instead of 32bit.\r\n* us_ticker API receiving time in microseconds, whereas RTC counting in units of 1/32Khz.\r\n\r\nPlease review and test. I have a suspicion extensive testing may reveal more hardware related quirks which haven't been taken care of.\r\n","created_at":"2015-02-25T21:38:03Z","updated_at":"2015-03-05T15:32:24Z","closed_at":null,"merged_at":null,"merge_commit_sha":"bd16cbf9ae58ab21bb59aa628a74f97c55bc30b7","assignee":{"login":"rgrover","id":112704,"avatar_url":"https://avatars.githubusercontent.com/u/112704?v=3","gravatar_id":"","url":"https://api.github.com/users/rgrover","html_url":"https://github.com/rgrover","followers_url":"https://api.github.com/users/rgrover/followers","following_url":"https://api.github.com/users/rgrover/following{/other_user}","gists_url":"https://api.github.com/users/rgrover/gists{/gist_id}","starred_url":"https://api.github.com/users/rgrover/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rgrover/subscriptions","organizations_url":"https://api.github.com/users/rgrover/orgs","repos_url":"https://api.github.com/users/rgrover/repos","events_url":"https://api.github.com/users/rgrover/events{/privacy}","received_events_url":"https://api.github.com/users/rgrover/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/mbedmicro/mbed/pulls/932/commits","review_comments_url":"https://api.github.com/repos/mbedmicro/mbed/pulls/932/comments","review_comment_url":"https://api.github.com/repos/mbedmicro/mbed/pulls/comments{/number}","comments_url":"https://api.github.com/repos/mbedmicro/mbed/issues/932/comments","statuses_url":"https://api.github.com/repos/mbedmicro/mbed/statuses/e01cb0ae84b8c1cefa1cac3a637147ac9bc2ee43","head":{"label":"rgrover:replaceAppTimer","ref":"replaceAppTimer","sha":"e01cb0ae84b8c1cefa1cac3a637147ac9bc2ee43","user":{"login":"rgrover","id":112704,"avatar_url":"https://avatars.githubusercontent.com/u/112704?v=3","gravatar_id":"","url":"https://api.github.com/users/rgrover","html_url":"https://github.com/rgrover","followers_url":"https://api.github.com/users/rgrover/followers","following_url":"https://api.github.com/users/rgrover/following{/other_user}","gists_url":"https://api.github.com/users/rgrover/gists{/gist_id}","starred_url":"https://api.github.com/users/rgrover/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rgrover/subscriptions","organizations_url":"https://api.github.com/users/rgrover/orgs","repos_url":"https://api.github.com/users/rgrover/repos","events_url":"https://api.github.com/users/rgrover/events{/privacy}","received_events_url":"https://api.github.com/users/rgrover/received_events","type":"User","site_admin":false},"repo":{"id":26175384,"name":"mbed","full_name":"rgrover/mbed","owner":{"login":"rgrover","id":112704,"avatar_url":"https://avatars.githubusercontent.com/u/112704?v=3","gravatar_id":"","url":"https://api.github.com/users/rgrover","html_url":"https://github.com/rgrover","followers_url":"https://api.github.com/users/rgrover/followers","following_url":"https://api.github.com/users/rgrover/following{/other_user}","gists_url":"https://api.github.com/users/rgrover/gists{/gist_id}","starred_url":"https://api.github.com/users/rgrover/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rgrover/subscriptions","organizations_url":"https://api.github.com/users/rgrover/orgs","repos_url":"https://api.github.com/users/rgrover/repos","events_url":"https://api.github.com/users/rgrover/events{/privacy}","received_events_url":"https://api.github.com/users/rgrover/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/rgrover/mbed","description":"mbed libraries and tools","fork":true,"url":"https://api.github.com/repos/rgrover/mbed","forks_url":"https://api.github.com/repos/rgrover/mbed/forks","keys_url":"https://api.github.com/repos/rgrover/mbed/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rgrover/mbed/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rgrover/mbed/teams","hooks_url":"https://api.github.com/repos/rgrover/mbed/hooks","issue_events_url":"https://api.github.com/repos/rgrover/mbed/issues/events{/number}","events_url":"https://api.github.com/repos/rgrover/mbed/events","assignees_url":"https://api.github.com/repos/rgrover/mbed/assignees{/user}","branches_url":"https://api.github.com/repos/rgrover/mbed/branches{/branch}","tags_url":"https://api.github.com/repos/rgrover/mbed/tags","blobs_url":"https://api.github.com/repos/rgrover/mbed/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rgrover/mbed/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rgrover/mbed/git/refs{/sha}","trees_url":"https://api.github.com/repos/rgrover/mbed/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rgrover/mbed/statuses/{sha}","languages_url":"https://api.github.com/repos/rgrover/mbed/languages","stargazers_url":"https://api.github.com/repos/rgrover/mbed/stargazers","contributors_url":"https://api.github.com/repos/rgrover/mbed/contributors","subscribers_url":"https://api.github.com/repos/rgrover/mbed/subscribers","subscription_url":"https://api.github.com/repos/rgrover/mbed/subscription","commits_url":"https://api.github.com/repos/rgrover/mbed/commits{/sha}","git_commits_url":"https://api.github.com/repos/rgrover/mbed/git/commits{/sha}","comments_url":"https://api.github.com/repos/rgrover/mbed/comments{/number}","issue_comment_url":"https://api.github.com/repos/rgrover/mbed/issues/comments{/number}","contents_url":"https://api.github.com/repos/rgrover/mbed/contents/{+path}","compare_url":"https://api.github.com/repos/rgrover/mbed/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rgrover/mbed/merges","archive_url":"https://api.github.com/repos/rgrover/mbed/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rgrover/mbed/downloads","issues_url":"https://api.github.com/repos/rgrover/mbed/issues{/number}","pulls_url":"https://api.github.com/repos/rgrover/mbed/pulls{/number}","milestones_url":"https://api.github.com/repos/rgrover/mbed/milestones{/number}","notifications_url":"https://api.github.com/repos/rgrover/mbed/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rgrover/mbed/labels{/name}","releases_url":"https://api.github.com/repos/rgrover/mbed/releases{/id}","created_at":"2014-11-04T15:37:29Z","updated_at":"2015-02-25T21:31:09Z","pushed_at":"2015-03-05T11:57:47Z","git_url":"git://github.com/rgrover/mbed.git","ssh_url":"git@github.com:rgrover/mbed.git","clone_url":"https://github.com/rgrover/mbed.git","svn_url":"https://github.com/rgrover/mbed","homepage":null,"size":21101,"stargazers_count":0,"watchers_count":0,"language":"C","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"mbedmicro:master","ref":"master","sha":"d6156f425b3fd9a4841bea869b21ca3d1ab78c09","user":{"login":"mbedmicro","id":3626466,"avatar_url":"https://avatars.githubusercontent.com/u/3626466?v=3","gravatar_id":"","url":"https://api.github.com/users/mbedmicro","html_url":"https://github.com/mbedmicro","followers_url":"https://api.github.com/users/mbedmicro/followers","following_url":"https://api.github.com/users/mbedmicro/following{/other_user}","gists_url":"https://api.github.com/users/mbedmicro/gists{/gist_id}","starred_url":"https://api.github.com/users/mbedmicro/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mbedmicro/subscriptions","organizations_url":"https://api.github.com/users/mbedmicro/orgs","repos_url":"https://api.github.com/users/mbedmicro/repos","events_url":"https://api.github.com/users/mbedmicro/events{/privacy}","received_events_url":"https://api.github.com/users/mbedmicro/received_events","type":"Organization","site_admin":false},"repo":{"id":8270972,"name":"mbed","full_name":"mbedmicro/mbed","owner":{"login":"mbedmicro","id":3626466,"avatar_url":"https://avatars.githubusercontent.com/u/3626466?v=3","gravatar_id":"","url":"https://api.github.com/users/mbedmicro","html_url":"https://github.com/mbedmicro","followers_url":"https://api.github.com/users/mbedmicro/followers","following_url":"https://api.github.com/users/mbedmicro/following{/other_user}","gists_url":"https://api.github.com/users/mbedmicro/gists{/gist_id}","starred_url":"https://api.github.com/users/mbedmicro/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mbedmicro/subscriptions","organizations_url":"https://api.github.com/users/mbedmicro/orgs","repos_url":"https://api.github.com/users/mbedmicro/repos","events_url":"https://api.github.com/users/mbedmicro/events{/privacy}","received_events_url":"https://api.github.com/users/mbedmicro/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/mbedmicro/mbed","description":"mbed libraries and tools","fork":false,"url":"https://api.github.com/repos/mbedmicro/mbed","forks_url":"https://api.github.com/repos/mbedmicro/mbed/forks","keys_url":"https://api.github.com/repos/mbedmicro/mbed/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mbedmicro/mbed/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mbedmicro/mbed/teams","hooks_url":"https://api.github.com/repos/mbedmicro/mbed/hooks","issue_events_url":"https://api.github.com/repos/mbedmicro/mbed/issues/events{/number}","events_url":"https://api.github.com/repos/mbedmicro/mbed/events","assignees_url":"https://api.github.com/repos/mbedmicro/mbed/assignees{/user}","branches_url":"https://api.github.com/repos/mbedmicro/mbed/branches{/branch}","tags_url":"https://api.github.com/repos/mbedmicro/mbed/tags","blobs_url":"https://api.github.com/repos/mbedmicro/mbed/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mbedmicro/mbed/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mbedmicro/mbed/git/refs{/sha}","trees_url":"https://api.github.com/repos/mbedmicro/mbed/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mbedmicro/mbed/statuses/{sha}","languages_url":"https://api.github.com/repos/mbedmicro/mbed/languages","stargazers_url":"https://api.github.com/repos/mbedmicro/mbed/stargazers","contributors_url":"https://api.github.com/repos/mbedmicro/mbed/contributors","subscribers_url":"https://api.github.com/repos/mbedmicro/mbed/subscribers","subscription_url":"https://api.github.com/repos/mbedmicro/mbed/subscription","commits_url":"https://api.github.com/repos/mbedmicro/mbed/commits{/sha}","git_commits_url":"https://api.github.com/repos/mbedmicro/mbed/git/commits{/sha}","comments_url":"https://api.github.com/repos/mbedmicro/mbed/comments{/number}","issue_comment_url":"https://api.github.com/repos/mbedmicro/mbed/issues/comments{/number}","contents_url":"https://api.github.com/repos/mbedmicro/mbed/contents/{+path}","compare_url":"https://api.github.com/repos/mbedmicro/mbed/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mbedmicro/mbed/merges","archive_url":"https://api.github.com/repos/mbedmicro/mbed/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mbedmicro/mbed/downloads","issues_url":"https://api.github.com/repos/mbedmicro/mbed/issues{/number}","pulls_url":"https://api.github.com/repos/mbedmicro/mbed/pulls{/number}","milestones_url":"https://api.github.com/repos/mbedmicro/mbed/milestones{/number}","notifications_url":"https://api.github.com/repos/mbedmicro/mbed/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mbedmicro/mbed/labels{/name}","releases_url":"https://api.github.com/repos/mbedmicro/mbed/releases{/id}","created_at":"2013-02-18T15:23:11Z","updated_at":"2015-03-05T13:05:07Z","pushed_at":"2015-03-05T13:05:06Z","git_url":"git://github.com/mbedmicro/mbed.git","ssh_url":"git@github.com:mbedmicro/mbed.git","clone_url":"https://github.com/mbedmicro/mbed.git","svn_url":"https://github.com/mbedmicro/mbed","homepage":null,"size":37681,"stargazers_count":348,"watchers_count":348,"language":"C","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":357,"mirror_url":null,"open_issues_count":75,"forks":357,"open_issues":75,"watchers":348,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/mbedmicro/mbed/pulls/932"},"html":{"href":"https://github.com/mbedmicro/mbed/pull/932"},"issue":{"href":"https://api.github.com/repos/mbedmicro/mbed/issues/932"},"comments":{"href":"https://api.github.com/repos/mbedmicro/mbed/issues/932/comments"},"review_comments":{"href":"https://api.github.com/repos/mbedmicro/mbed/pulls/932/comments"},"review_comment":{"href":"https://api.github.com/repos/mbedmicro/mbed/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/mbedmicro/mbed/pulls/932/commits"},"statuses":{"href":"https://api.github.com/repos/mbedmicro/mbed/statuses/e01cb0ae84b8c1cefa1cac3a637147ac9bc2ee43"}}}}