summaryrefslogtreecommitdiffhomepage
path: root/digital/ucoolib/ucoolib
diff options
context:
space:
mode:
authorNicolas Schodet2013-02-26 00:14:44 +0100
committerNicolas Schodet2013-03-01 22:58:04 +0100
commitd4107fb0d958f870e79421f507908be5f20d13e2 (patch)
tree3b6cfb4f6a51eae5095dd74fd093ae6fbf92a6aa /digital/ucoolib/ucoolib
parent3a4bd5948939030b960c3363c04a33032d517fc7 (diff)
digital/ucoolib/ucoolib/hal/i2c: add host implementation
Diffstat (limited to 'digital/ucoolib/ucoolib')
-rw-r--r--digital/ucoolib/ucoolib/hal/i2c/Module2
-rw-r--r--digital/ucoolib/ucoolib/hal/i2c/i2c.hh4
-rw-r--r--digital/ucoolib/ucoolib/hal/i2c/i2c.host.cc213
-rw-r--r--digital/ucoolib/ucoolib/hal/i2c/i2c.host.hh66
-rw-r--r--digital/ucoolib/ucoolib/hal/i2c/test/Makefile2
-rw-r--r--digital/ucoolib/ucoolib/hal/i2c/test/hub.py6
-rw-r--r--digital/ucoolib/ucoolib/hal/i2c/test/test_i2c.cc45
7 files changed, 320 insertions, 18 deletions
diff --git a/digital/ucoolib/ucoolib/hal/i2c/Module b/digital/ucoolib/ucoolib/hal/i2c/Module
index d502c4a0..ae93f228 100644
--- a/digital/ucoolib/ucoolib/hal/i2c/Module
+++ b/digital/ucoolib/ucoolib/hal/i2c/Module
@@ -1 +1 @@
-hal_i2c_SOURCES := i2c_slave_data_buffer.cc i2c_hard.stm32.cc
+hal_i2c_SOURCES := i2c.host.cc i2c_slave_data_buffer.cc i2c_hard.stm32.cc
diff --git a/digital/ucoolib/ucoolib/hal/i2c/i2c.hh b/digital/ucoolib/ucoolib/hal/i2c/i2c.hh
index 963eb767..5fad9988 100644
--- a/digital/ucoolib/ucoolib/hal/i2c/i2c.hh
+++ b/digital/ucoolib/ucoolib/hal/i2c/i2c.hh
@@ -24,7 +24,9 @@
//
// }}}
-#if defined (TARGET_stm32)
+#if defined (TARGET_host)
+# include "i2c.host.hh"
+#elif defined (TARGET_stm32)
# include "i2c_hard.stm32.hh"
#else
# error "not implemented for this target"
diff --git a/digital/ucoolib/ucoolib/hal/i2c/i2c.host.cc b/digital/ucoolib/ucoolib/hal/i2c/i2c.host.cc
new file mode 100644
index 00000000..1ad5f9e9
--- /dev/null
+++ b/digital/ucoolib/ucoolib/hal/i2c/i2c.host.cc
@@ -0,0 +1,213 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// APBTeam:
+// Web: http://apbteam.org/
+// Email: team AT apbteam DOT org
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// }}}
+#include "i2c.host.hh"
+
+#include "config/hal/i2c.hh"
+
+namespace ucoo {
+
+/// Shared context between instances.
+class I2cHostShared
+{
+ public:
+ /// Constructor, connect to mex node.
+ I2cHostShared (Host &host);
+ /// Register a new driver instance.
+ void register_instance (Host &host, I2cHost &instance);
+ /// Send message, return new master status.
+ int send (uint8_t addr, const char *buf, int count);
+ /// Receive message, return new master status.
+ int recv (uint8_t addr, char *buf, int count);
+ /// Handle read requests from master.
+ void handle_read (mex::Msg &msg);
+ /// Handle write requests from master.
+ void handle_write (mex::Msg &msg);
+ private:
+ Host &host_;
+ mex::Node &node_;
+ mex::mtype_t read_mtype_, write_mtype_;
+ typedef std::list<I2cHost *> Instances;
+ Instances instances_;
+};
+
+I2cHostShared::I2cHostShared (Host &host)
+ : host_ (host), node_ (host.get_node ())
+{
+ std::string instance = host_.get_instance (1);
+ read_mtype_ = node_.reserve (instance + ":read");
+ write_mtype_ = node_.reserve (instance + ":write");
+ node_.handler_register (read_mtype_, *this, &I2cHostShared::handle_read);
+ node_.handler_register (write_mtype_, *this, &I2cHostShared::handle_write);
+}
+
+void
+I2cHostShared::register_instance (Host &host, I2cHost &instance)
+{
+ assert (&host == &host_);
+ instances_.push_back (&instance);
+}
+
+int
+I2cHostShared::send (uint8_t addr, const char *buf, int count)
+{
+ // Test for this slave in the same program.
+ for (Instances::const_iterator i = instances_.begin ();
+ i != instances_.end (); ++i)
+ {
+ if (addr == (*i)->slave_addr_)
+ {
+ assert (count <= UCOO_CONFIG_HAL_I2C_SLAVE_BUFFER_SIZE);
+ (*i)->slave_data_handler_->to_recv (buf, count);
+ return count;
+ }
+ }
+ // Else, send message.
+ mex::Msg msg (write_mtype_);
+ msg.push ("B") << addr;
+ msg.push (buf, count);
+ node_.send (msg);
+ return count;
+}
+
+int
+I2cHostShared::recv (uint8_t addr, char *buf, int count)
+{
+ // Test for this slave in the same program.
+ for (Instances::const_iterator i = instances_.begin ();
+ i != instances_.end (); ++i)
+ {
+ if (addr == (*i)->slave_addr_)
+ {
+ assert (count <= UCOO_CONFIG_HAL_I2C_SLAVE_BUFFER_SIZE);
+ return (*i)->slave_data_handler_->to_send (buf, count);
+ }
+ }
+ // Else, send request and wait for response.
+ mex::Msg msg (read_mtype_);
+ msg.push ("BB") << addr << count;
+ std::auto_ptr<mex::Msg> rsp = node_.request (msg);
+ int rcount = rsp->len ();
+ assert (rcount <= count);
+ const char *rbuf = rsp->pop (rcount);
+ std::copy (rbuf, rbuf + rcount, buf);
+ return rcount;
+}
+
+void
+I2cHostShared::handle_read (mex::Msg &msg)
+{
+ uint8_t addr;
+ int size;
+ msg.pop ("BB") >> addr >> size;
+ for (Instances::const_iterator i = instances_.begin ();
+ i != instances_.end (); ++i)
+ {
+ if (addr == (*i)->slave_addr_)
+ {
+ assert (size <= UCOO_CONFIG_HAL_I2C_SLAVE_BUFFER_SIZE);
+ char buf[size];
+ int n = (*i)->slave_data_handler_->to_send (buf, size);
+ mex::Msg rsp (read_mtype_);
+ rsp.push (buf, n);
+ node_.response (rsp);
+ break;
+ }
+ }
+}
+
+void
+I2cHostShared::handle_write (mex::Msg &msg)
+{
+ uint8_t addr;
+ msg.pop ("B") >> addr;
+ for (Instances::const_iterator i = instances_.begin ();
+ i != instances_.end (); ++i)
+ {
+ if (addr == (*i)->slave_addr_)
+ {
+ int size = msg.len ();
+ assert (size <= UCOO_CONFIG_HAL_I2C_SLAVE_BUFFER_SIZE);
+ (*i)->slave_data_handler_->to_recv (msg.pop (size), size);
+ break;
+ }
+ }
+}
+
+I2cHostShared *I2cHost::shared_;
+
+I2cHost::I2cHost (Host &host, int n)
+ : n_ (n), slave_addr_ (0), slave_data_handler_ (0),
+ master_status_ (STATUS_ERROR)
+{
+ if (!shared_)
+ {
+ static I2cHostShared shared (host);
+ shared_ = &shared;
+ }
+ shared_->register_instance (host, *this);
+ // n is not used, there is no support for several buses in the MEX
+ // messages at the moment.
+}
+
+void
+I2cHost::send (uint8_t addr, const char *buf, int count)
+{
+ // Update status, there is no background task.
+ master_status_ = shared_->send (addr, buf, count);
+ // If needed, call callback.
+ if (finished_handler_)
+ finished_handler_->finished (master_status_);
+}
+
+void
+I2cHost::recv (uint8_t addr, char *buf, int count)
+{
+ // Update status, there is no background task.
+ master_status_ = shared_->recv (addr, buf, count);
+ // If needed, call callback.
+ if (finished_handler_)
+ finished_handler_->finished (master_status_);
+}
+
+int
+I2cHost::status ()
+{
+ return master_status_;
+}
+
+int
+I2cHost::wait ()
+{
+ // Transfers are immediate.
+ return status ();
+}
+
+void
+I2cHost::register_data (uint8_t addr, DataHandler &data_handler)
+{
+ slave_addr_ = addr;
+ slave_data_handler_ = &data_handler;
+}
+
+} // namespace ucoo
diff --git a/digital/ucoolib/ucoolib/hal/i2c/i2c.host.hh b/digital/ucoolib/ucoolib/hal/i2c/i2c.host.hh
new file mode 100644
index 00000000..47a802b9
--- /dev/null
+++ b/digital/ucoolib/ucoolib/hal/i2c/i2c.host.hh
@@ -0,0 +1,66 @@
+#ifndef ucoolib_hal_i2c_i2c_host_hh
+#define ucoolib_hal_i2c_i2c_host_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// APBTeam:
+// Web: http://apbteam.org/
+// Email: team AT apbteam DOT org
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// }}}
+#include "ucoolib/intf/i2c.hh"
+#include "ucoolib/arch/host/host.hh"
+
+namespace ucoo {
+
+class I2cHostShared;
+
+/// I2C interface, host version.
+class I2cHost : public I2c
+{
+ public:
+ /// Initialise the Nth I2C.
+ I2cHost (Host &host, int n);
+ /// See I2cMaster::send.
+ void send (uint8_t addr, const char *buf, int count);
+ /// See I2cMaster::recv.
+ void recv (uint8_t addr, char *buf, int count);
+ /// See I2cMaster::status.
+ int status ();
+ /// See I2cMaster::wait.
+ int wait ();
+ /// See I2cSlave::register_data.
+ void register_data (uint8_t addr, DataHandler &data_handler);
+ private:
+ /// I2C number.
+ int n_;
+ /// Slave address.
+ uint8_t slave_addr_;
+ /// Handler called to source or sink data for slave exchanges.
+ DataHandler *slave_data_handler_;
+ /// Current master transfer status.
+ int master_status_;
+ /// Shared context.
+ static I2cHostShared *shared_;
+ friend class I2cHostShared;
+};
+
+} // namespace ucoo
+
+
+#endif // ucoolib_hal_i2c_i2c_host_hh
diff --git a/digital/ucoolib/ucoolib/hal/i2c/test/Makefile b/digital/ucoolib/ucoolib/hal/i2c/test/Makefile
index 14a46120..50468624 100644
--- a/digital/ucoolib/ucoolib/hal/i2c/test/Makefile
+++ b/digital/ucoolib/ucoolib/hal/i2c/test/Makefile
@@ -1,6 +1,6 @@
BASE = ../../../..
-TARGETS = stm32f4
+TARGETS = host stm32f4
PROGS = test_i2c
test_i2c_SOURCES = test_i2c.cc
diff --git a/digital/ucoolib/ucoolib/hal/i2c/test/hub.py b/digital/ucoolib/ucoolib/hal/i2c/test/hub.py
new file mode 100644
index 00000000..c6c77f77
--- /dev/null
+++ b/digital/ucoolib/ucoolib/hal/i2c/test/hub.py
@@ -0,0 +1,6 @@
+# Hub for test.
+from mex.hub import Hub
+def log (x):
+ print x
+h = Hub (min_clients = 1, log = log)
+h.wait ()
diff --git a/digital/ucoolib/ucoolib/hal/i2c/test/test_i2c.cc b/digital/ucoolib/ucoolib/hal/i2c/test/test_i2c.cc
index dd043f32..4a99a419 100644
--- a/digital/ucoolib/ucoolib/hal/i2c/test/test_i2c.cc
+++ b/digital/ucoolib/ucoolib/hal/i2c/test/test_i2c.cc
@@ -24,11 +24,14 @@
#include "ucoolib/hal/i2c/i2c.hh"
#include "ucoolib/arch/arch.hh"
-#include "ucoolib/hal/gpio/gpio.hh"
-#include "ucoolib/utils/delay.hh"
#include "ucoolib/base/test/test.hh"
-#include <libopencm3/stm32/f4/rcc.h>
+#ifdef TARGET_stm32
+# include <libopencm3/stm32/f4/rcc.h>
+# include "ucoolib/hal/gpio/gpio.hh"
+#endif
+
+#include "ucoolib/utils/delay.hh"
#include <algorithm>
#include <cstring>
@@ -44,23 +47,28 @@ test_basic (ucoo::TestSuite &tsuite, ucoo::I2cMaster &m,
tsuite.group ("basic");
{
ucoo::Test test (tsuite, "recv");
- // Slave is not able to signal its buffer end. Extra bytes will be
- // read as 0xff.
const char *hello = "Hello world!";
char buf[buffer_size + margin];
d.update (hello, std::strlen (hello) + 1);
char ref[buffer_size + margin];
- std::copy (hello, hello + std::strlen (hello) + 1, ref);
- std::fill (ref + std::strlen (hello) + 1, ref + sizeof (ref), 0xff);
+ int ref_size = std::strlen (hello) + 1;
+ std::copy (hello, hello + ref_size, ref);
+#ifdef TARGET_stm32
+ // Slave is not able to signal its buffer end. Extra bytes will be
+ // read as 0xff.
+ std::fill (ref + ref_size, ref + sizeof (ref), 0xff);
+ ref_size = sizeof (ref);
+#endif
for (int len = 2; len < (int) sizeof (buf); len++)
{
std::fill (buf, buf + sizeof (buf), 42);
m.recv (addr, buf, len);
int r = m.wait ();
- test_fail_break_unless (test, r == len);
- test_fail_break_unless (test, std::equal (buf, buf + len, ref));
+ int rexp = std::min (len, ref_size);
+ test_fail_break_unless (test, r == rexp);
+ test_fail_break_unless (test, std::equal (buf, buf + rexp, ref));
test_fail_break_unless (test, std::count (buf, buf + sizeof (buf), 42)
- == (int) sizeof (buf) - len);
+ == (int) sizeof (buf) - rexp);
}
}
{
@@ -112,12 +120,12 @@ test_basic (ucoo::TestSuite &tsuite, ucoo::I2cMaster &m,
switch (step_)
{
case 0:
- m_.recv (addr_, buf_, buffer_size);
step_++;
+ m_.recv (addr_, buf_, buffer_size);
break;
case 1:
- m_.send (addr_, buf_, buffer_size);
step_++;
+ m_.send (addr_, buf_, buffer_size);
break;
case 2:
// Nothing, stop.
@@ -154,6 +162,12 @@ main (int argc, const char **argv)
{
ucoo::arch_init (argc, argv);
ucoo::TestSuite tsuite ("i2c");
+#if defined (TARGET_host)
+ ucoo::Host host ("test_i2c");
+ host.parse_options ();
+ ucoo::I2cHost i2c1 (host, 0);
+ ucoo::I2cHost i2c2 (host, 1);
+#elif defined (TARGET_stm32)
// I2C1: B6: SCL, B9: SDA
// I2C3: A8: SCL, C9: SDA
rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN);
@@ -168,13 +182,14 @@ main (int argc, const char **argv)
gpio_set_af (GPIOB, GPIO_AF4, GPIO6 | GPIO9);
gpio_set_af (GPIOA, GPIO_AF4, GPIO8);
gpio_set_af (GPIOC, GPIO_AF4, GPIO9);
- ucoo::I2cSlaveDataBufferSize<16, 16> data1, data2;
ucoo::I2cHard i2c1 (0);
ucoo::I2cHard i2c2 (2);
- i2c1.register_data (a1, data1);
- i2c2.register_data (a2, data2);
i2c1.enable ();
i2c2.enable ();
+#endif
+ ucoo::I2cSlaveDataBufferSize<16, 16> data1, data2;
+ i2c1.register_data (a1, data1);
+ i2c2.register_data (a2, data2);
// Run tests.
test_basic (tsuite, i2c1, data2, a2);
test_basic (tsuite, i2c2, data1, a1);