{"action":"created","comment":{"url":"https://api.github.com/repos/ARMmbed/mbed-drivers/pulls/comments/51762072","id":51762072,"diff_hunk":"@@ -0,0 +1,258 @@\n+/* mbed Microcontroller Library\n+ * Copyright (c) 2016 ARM Limited\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ *     http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+#include \"mbed-drivers/v1/I2CDetail.hpp\"\n+\n+#if DEVICE_I2C && DEVICE_I2C_ASYNCH\n+\n+#include \"mbed-drivers/v1/I2C.hpp\"\n+#include \"core-util/CriticalSectionLock.h\"\n+#include \"minar/minar.h\"\n+\n+namespace mbed_drivers {\n+using namespace mbed;\n+namespace v1 {\n+namespace detail {\n+\n+int I2CResourceManager::post_transaction(I2CTransaction *t) {\n+    int rc;\n+    if ((rc = validate_transaction(t))) {\n+        return rc;\n+    }\n+    // Optimization NOTE: this could be lock-free with atomic_cas.\n+    mbed::util::CriticalSectionLock lock;\n+    // Find the tail of the queue\n+    I2CTransaction * tx = (I2CTransaction *)TransactionQueue;\n+    if (!tx) {\n+        TransactionQueue = t;\n+        power_up();\n+        start_transaction();\n+        return 0;\n+    }\n+    while (tx->next) {\n+        tx = tx->next;\n+    }\n+    tx->next = t;\n+    return 0;\n+}\n+\n+void I2CResourceManager::process_event(int event) {\n+    I2CTransaction * t;\n+    CORE_UTIL_ASSERT(TransactionQueue != nullptr);\n+    if (!TransactionQueue) {\n+        return;\n+    }\n+    // Get the current item in the transaction queue\n+    t = (I2CTransaction *) TransactionQueue;\n+    if (!t) {\n+        return;\n+    }\n+    // Fire the irqcallback for the segment\n+    t->current->call_irq_cb();\n+    // If there was an event that is not a complete event\n+    // or there was a complete event and the next segment is nullptr\n+    if ((event & I2C_EVENT_ALL & ~I2C_EVENT_TRANSFER_COMPLETE) ||\n+        ((event & I2C_EVENT_TRANSFER_COMPLETE) && t->current->get_next() == nullptr))\n+    {\n+        // fire the handler\n+        using cbtype = mbed::util::FunctionPointer2<void,I2CTransaction *, int>;\n+        minar::Scheduler::postCallback(cbtype(this, &I2CResourceManager::event_cb).bind(t,event));\n+        // TODO: This could be lock-free\n+        // Enter a critical section\n+        mbed::util::CriticalSectionLock lock;\n+        // Advance to the next transaction\n+        TransactionQueue = t->next;\n+        if (TransactionQueue) {\n+            // Initiate the next transaction\n+            start_transaction();\n+        } else {\n+            power_down();\n+        }\n+    } else {\n+        // TODO: this could be lock-free\n+        mbed::util::CriticalSectionLock lock;\n+        t->current = t->current->get_next();\n+        start_segment();\n+    }\n+}\n+void I2CResourceManager::event_cb(I2CTransaction * t, int event) {\n+    // TODO: Should these be else-ifs?\n+    if (event & I2C_EVENT_ERROR_NO_SLAVE) {\n+        t->_noslaveCB(t, event);\n+    }\n+    if (event & I2C_EVENT_TRANSFER_EARLY_NACK) {\n+        t->_nakCB(t, event);\n+    }\n+    if (event & I2C_EVENT_ERROR) {\n+        t->_errorCB(t, event);\n+    }\n+    if (event & I2C_EVENT_TRANSFER_COMPLETE) {\n+        t->_doneCB(t, event);\n+    }\n+    t->issuer->free(t);\n+}\n+\n+\n+I2CResourceManager::I2CResourceManager() : TransactionQueue(nullptr) {}\n+I2CResourceManager::~I2CResourceManager() {\n+    while (TransactionQueue) {\n+        I2CTransaction * tx = (I2CTransaction *)(TransactionQueue);\n+        TransactionQueue = tx->next;\n+        tx->issuer->free(tx);\n+    }\n+}\n+\n+class HWI2CResourceManager : public I2CResourceManager {\n+public:\n+    HWI2CResourceManager(const size_t id, void(*handler)(void)):\n+        _i2c(),\n+        _id(id),\n+        _usage(DMA_USAGE_NEVER),\n+        _inited(false),\n+        _handler(handler)\n+    {\n+    }\n+    int init(PinName sda, PinName scl) {\n+        // calling init during a transaction could cause communication artifacts\n+        if (!_inited) {\n+            // The init function also set the frequency to 100000\n+            i2c_init(&_i2c, sda, scl);\n+            _inited = true;\n+        } else {\n+            // Only support an I2C master on a single pair of pins\n+            if (_scl != scl || _sda != sda) {\n+                return -1;\n+            }\n+        }\n+        return 0;\n+    }\n+    int start_segment () {\n+        I2CTransaction * t = (I2CTransaction *)TransactionQueue;\n+        if (!t) {\n+            return -1;\n+        }\n+        I2CSegment * s = t->current;\n+        if (!s) {\n+            return -1;\n+        }\n+        bool stop = (s->get_next() == nullptr) && (!t->repeated);\n+        if (s->get_dir() == I2CDirection::Transmit) {\n+            i2c_transfer_asynch(&_i2c, s->get_buf(), s->get_len(), nullptr, 0, t->address,\n+                stop, (uint32_t)_handler, I2C_EVENT_ALL, _usage);\n+        } else {\n+            i2c_transfer_asynch(&_i2c, nullptr, 0, s->get_buf(), s->get_len(), t->address,\n+                stop, (uint32_t)_handler, I2C_EVENT_ALL, _usage);\n+        }\n+        return 0;\n+    }\n+    int start_transaction() {\n+        // TODO: This needs a higher-level start/stop lock","path":"source/v1/I2CDetail.cpp","position":162,"original_position":162,"commit_id":"254507aae6c2bba7108bd1625fbcf9f4d85e64c1","original_commit_id":"254507aae6c2bba7108bd1625fbcf9f4d85e64c1","user":{"login":"bremoran","id":2636227,"avatar_url":"https://avatars.githubusercontent.com/u/2636227?v=3","gravatar_id":"","url":"https://api.github.com/users/bremoran","html_url":"https://github.com/bremoran","followers_url":"https://api.github.com/users/bremoran/followers","following_url":"https://api.github.com/users/bremoran/following{/other_user}","gists_url":"https://api.github.com/users/bremoran/gists{/gist_id}","starred_url":"https://api.github.com/users/bremoran/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bremoran/subscriptions","organizations_url":"https://api.github.com/users/bremoran/orgs","repos_url":"https://api.github.com/users/bremoran/repos","events_url":"https://api.github.com/users/bremoran/events{/privacy}","received_events_url":"https://api.github.com/users/bremoran/received_events","type":"User","site_admin":false},"body":"Please assume that any TODO's remaining in this changeset are on my list for the next patch.","created_at":"2016-02-03T18:12:50Z","updated_at":"2016-02-03T18:12:50Z","html_url":"https://github.com/ARMmbed/mbed-drivers/pull/102#discussion_r51762072","pull_request_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/pulls/102","_links":{"self":{"href":"https://api.github.com/repos/ARMmbed/mbed-drivers/pulls/comments/51762072"},"html":{"href":"https://github.com/ARMmbed/mbed-drivers/pull/102#discussion_r51762072"},"pull_request":{"href":"https://api.github.com/repos/ARMmbed/mbed-drivers/pulls/102"}}},"pull_request":{"url":"https://api.github.com/repos/ARMmbed/mbed-drivers/pulls/102","id":47501715,"html_url":"https://github.com/ARMmbed/mbed-drivers/pull/102","diff_url":"https://github.com/ARMmbed/mbed-drivers/pull/102.diff","patch_url":"https://github.com/ARMmbed/mbed-drivers/pull/102.patch","issue_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/issues/102","number":102,"state":"open","locked":false,"title":"Add a prototype fluent API for I2C","user":{"login":"bremoran","id":2636227,"avatar_url":"https://avatars.githubusercontent.com/u/2636227?v=3","gravatar_id":"","url":"https://api.github.com/users/bremoran","html_url":"https://github.com/bremoran","followers_url":"https://api.github.com/users/bremoran/followers","following_url":"https://api.github.com/users/bremoran/following{/other_user}","gists_url":"https://api.github.com/users/bremoran/gists{/gist_id}","starred_url":"https://api.github.com/users/bremoran/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bremoran/subscriptions","organizations_url":"https://api.github.com/users/bremoran/orgs","repos_url":"https://api.github.com/users/bremoran/repos","events_url":"https://api.github.com/users/bremoran/events{/privacy}","received_events_url":"https://api.github.com/users/bremoran/received_events","type":"User","site_admin":false},"body":"Much in the same vein as https://github.com/ARMmbed/mbed-drivers/pull/93, add a fluent API to I2C\r\n\r\ncc @0xc0170 @bogdanm @salkinium @hugovincent @autopulated ","created_at":"2015-10-13T08:02:46Z","updated_at":"2016-02-03T18:12:50Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c9dfac82a1d2978255183311781efa0090beef9a","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/pulls/102/commits","review_comments_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/pulls/102/comments","review_comment_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/pulls/comments{/number}","comments_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/issues/102/comments","statuses_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/statuses/254507aae6c2bba7108bd1625fbcf9f4d85e64c1","head":{"label":"bremoran:i2c-fluent","ref":"i2c-fluent","sha":"254507aae6c2bba7108bd1625fbcf9f4d85e64c1","user":{"login":"bremoran","id":2636227,"avatar_url":"https://avatars.githubusercontent.com/u/2636227?v=3","gravatar_id":"","url":"https://api.github.com/users/bremoran","html_url":"https://github.com/bremoran","followers_url":"https://api.github.com/users/bremoran/followers","following_url":"https://api.github.com/users/bremoran/following{/other_user}","gists_url":"https://api.github.com/users/bremoran/gists{/gist_id}","starred_url":"https://api.github.com/users/bremoran/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bremoran/subscriptions","organizations_url":"https://api.github.com/users/bremoran/orgs","repos_url":"https://api.github.com/users/bremoran/repos","events_url":"https://api.github.com/users/bremoran/events{/privacy}","received_events_url":"https://api.github.com/users/bremoran/received_events","type":"User","site_admin":false},"repo":{"id":42716978,"name":"mbed-drivers","full_name":"bremoran/mbed-drivers","owner":{"login":"bremoran","id":2636227,"avatar_url":"https://avatars.githubusercontent.com/u/2636227?v=3","gravatar_id":"","url":"https://api.github.com/users/bremoran","html_url":"https://github.com/bremoran","followers_url":"https://api.github.com/users/bremoran/followers","following_url":"https://api.github.com/users/bremoran/following{/other_user}","gists_url":"https://api.github.com/users/bremoran/gists{/gist_id}","starred_url":"https://api.github.com/users/bremoran/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bremoran/subscriptions","organizations_url":"https://api.github.com/users/bremoran/orgs","repos_url":"https://api.github.com/users/bremoran/repos","events_url":"https://api.github.com/users/bremoran/events{/privacy}","received_events_url":"https://api.github.com/users/bremoran/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/bremoran/mbed-drivers","description":"Drivers for common MCU peripherals in mbed OS.","fork":true,"url":"https://api.github.com/repos/bremoran/mbed-drivers","forks_url":"https://api.github.com/repos/bremoran/mbed-drivers/forks","keys_url":"https://api.github.com/repos/bremoran/mbed-drivers/keys{/key_id}","collaborators_url":"https://api.github.com/repos/bremoran/mbed-drivers/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/bremoran/mbed-drivers/teams","hooks_url":"https://api.github.com/repos/bremoran/mbed-drivers/hooks","issue_events_url":"https://api.github.com/repos/bremoran/mbed-drivers/issues/events{/number}","events_url":"https://api.github.com/repos/bremoran/mbed-drivers/events","assignees_url":"https://api.github.com/repos/bremoran/mbed-drivers/assignees{/user}","branches_url":"https://api.github.com/repos/bremoran/mbed-drivers/branches{/branch}","tags_url":"https://api.github.com/repos/bremoran/mbed-drivers/tags","blobs_url":"https://api.github.com/repos/bremoran/mbed-drivers/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/bremoran/mbed-drivers/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/bremoran/mbed-drivers/git/refs{/sha}","trees_url":"https://api.github.com/repos/bremoran/mbed-drivers/git/trees{/sha}","statuses_url":"https://api.github.com/repos/bremoran/mbed-drivers/statuses/{sha}","languages_url":"https://api.github.com/repos/bremoran/mbed-drivers/languages","stargazers_url":"https://api.github.com/repos/bremoran/mbed-drivers/stargazers","contributors_url":"https://api.github.com/repos/bremoran/mbed-drivers/contributors","subscribers_url":"https://api.github.com/repos/bremoran/mbed-drivers/subscribers","subscription_url":"https://api.github.com/repos/bremoran/mbed-drivers/subscription","commits_url":"https://api.github.com/repos/bremoran/mbed-drivers/commits{/sha}","git_commits_url":"https://api.github.com/repos/bremoran/mbed-drivers/git/commits{/sha}","comments_url":"https://api.github.com/repos/bremoran/mbed-drivers/comments{/number}","issue_comment_url":"https://api.github.com/repos/bremoran/mbed-drivers/issues/comments{/number}","contents_url":"https://api.github.com/repos/bremoran/mbed-drivers/contents/{+path}","compare_url":"https://api.github.com/repos/bremoran/mbed-drivers/compare/{base}...{head}","merges_url":"https://api.github.com/repos/bremoran/mbed-drivers/merges","archive_url":"https://api.github.com/repos/bremoran/mbed-drivers/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/bremoran/mbed-drivers/downloads","issues_url":"https://api.github.com/repos/bremoran/mbed-drivers/issues{/number}","pulls_url":"https://api.github.com/repos/bremoran/mbed-drivers/pulls{/number}","milestones_url":"https://api.github.com/repos/bremoran/mbed-drivers/milestones{/number}","notifications_url":"https://api.github.com/repos/bremoran/mbed-drivers/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/bremoran/mbed-drivers/labels{/name}","releases_url":"https://api.github.com/repos/bremoran/mbed-drivers/releases{/id}","deployments_url":"https://api.github.com/repos/bremoran/mbed-drivers/deployments","created_at":"2015-09-18T11:13:18Z","updated_at":"2015-09-18T11:13:20Z","pushed_at":"2016-02-02T16:50:01Z","git_url":"git://github.com/bremoran/mbed-drivers.git","ssh_url":"git@github.com:bremoran/mbed-drivers.git","clone_url":"https://github.com/bremoran/mbed-drivers.git","svn_url":"https://github.com/bremoran/mbed-drivers","homepage":"","size":18288,"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":"ARMmbed:master","ref":"master","sha":"3f6fb0d30fa9ee7816b93dbbb73990df0223a46c","user":{"login":"ARMmbed","id":8916057,"avatar_url":"https://avatars.githubusercontent.com/u/8916057?v=3","gravatar_id":"","url":"https://api.github.com/users/ARMmbed","html_url":"https://github.com/ARMmbed","followers_url":"https://api.github.com/users/ARMmbed/followers","following_url":"https://api.github.com/users/ARMmbed/following{/other_user}","gists_url":"https://api.github.com/users/ARMmbed/gists{/gist_id}","starred_url":"https://api.github.com/users/ARMmbed/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ARMmbed/subscriptions","organizations_url":"https://api.github.com/users/ARMmbed/orgs","repos_url":"https://api.github.com/users/ARMmbed/repos","events_url":"https://api.github.com/users/ARMmbed/events{/privacy}","received_events_url":"https://api.github.com/users/ARMmbed/received_events","type":"Organization","site_admin":false},"repo":{"id":27869497,"name":"mbed-drivers","full_name":"ARMmbed/mbed-drivers","owner":{"login":"ARMmbed","id":8916057,"avatar_url":"https://avatars.githubusercontent.com/u/8916057?v=3","gravatar_id":"","url":"https://api.github.com/users/ARMmbed","html_url":"https://github.com/ARMmbed","followers_url":"https://api.github.com/users/ARMmbed/followers","following_url":"https://api.github.com/users/ARMmbed/following{/other_user}","gists_url":"https://api.github.com/users/ARMmbed/gists{/gist_id}","starred_url":"https://api.github.com/users/ARMmbed/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ARMmbed/subscriptions","organizations_url":"https://api.github.com/users/ARMmbed/orgs","repos_url":"https://api.github.com/users/ARMmbed/repos","events_url":"https://api.github.com/users/ARMmbed/events{/privacy}","received_events_url":"https://api.github.com/users/ARMmbed/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/ARMmbed/mbed-drivers","description":"Drivers for common MCU peripherals in mbed OS.","fork":false,"url":"https://api.github.com/repos/ARMmbed/mbed-drivers","forks_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/forks","keys_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/teams","hooks_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/hooks","issue_events_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/issues/events{/number}","events_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/events","assignees_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/assignees{/user}","branches_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/branches{/branch}","tags_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/tags","blobs_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/git/refs{/sha}","trees_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/statuses/{sha}","languages_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/languages","stargazers_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/stargazers","contributors_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/contributors","subscribers_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/subscribers","subscription_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/subscription","commits_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/commits{/sha}","git_commits_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/git/commits{/sha}","comments_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/comments{/number}","issue_comment_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/issues/comments{/number}","contents_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/contents/{+path}","compare_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/merges","archive_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/downloads","issues_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/issues{/number}","pulls_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/pulls{/number}","milestones_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/milestones{/number}","notifications_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/labels{/name}","releases_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/releases{/id}","deployments_url":"https://api.github.com/repos/ARMmbed/mbed-drivers/deployments","created_at":"2014-12-11T11:59:33Z","updated_at":"2016-01-21T15:45:24Z","pushed_at":"2016-02-03T14:23:10Z","git_url":"git://github.com/ARMmbed/mbed-drivers.git","ssh_url":"git@github.com:ARMmbed/mbed-drivers.git","clone_url":"https://github.com/ARMmbed/mbed-drivers.git","svn_url":"https://github.com/ARMmbed/mbed-drivers","homepage":"","size":19701,"stargazers_count":22,"watchers_count":22,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":24,"mirror_url":null,"open_issues_count":24,"forks":24,"open_issues":24,"watchers":22,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/ARMmbed/mbed-drivers/pulls/102"},"html":{"href":"https://github.com/ARMmbed/mbed-drivers/pull/102"},"issue":{"href":"https://api.github.com/repos/ARMmbed/mbed-drivers/issues/102"},"comments":{"href":"https://api.github.com/repos/ARMmbed/mbed-drivers/issues/102/comments"},"review_comments":{"href":"https://api.github.com/repos/ARMmbed/mbed-drivers/pulls/102/comments"},"review_comment":{"href":"https://api.github.com/repos/ARMmbed/mbed-drivers/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/ARMmbed/mbed-drivers/pulls/102/commits"},"statuses":{"href":"https://api.github.com/repos/ARMmbed/mbed-drivers/statuses/254507aae6c2bba7108bd1625fbcf9f4d85e64c1"}}}}