dol: initial dol commit
[jump.git] / dol / src / dol / visitor / hdsd / scd / scd_cont_slave_wrapper.cpp
diff --git a/dol/src/dol/visitor/hdsd/scd/scd_cont_slave_wrapper.cpp b/dol/src/dol/visitor/hdsd/scd/scd_cont_slave_wrapper.cpp
new file mode 100644 (file)
index 0000000..0bc710a
--- /dev/null
@@ -0,0 +1,182 @@
+#include "scd_cont_slave_wrapper.h"
+
+#include "scd_logging.h"
+#include "scd_exception.h"
+
+
+scd_cont_slave_wrapper::scd_cont_slave_wrapper(scd_simulator& sim,
+        const std::string& name):
+    _sim(sim), scd_cont_fsm(name), _name(name), _is_connected(false),
+    _st_init(sim, *this), _st_busy(sim, *this), _st_idle(sim, *this),
+    _st_done(sim, *this), _st_time_req(sim, *this), _st_time_ack(sim, *this),
+    _st_term_req(sim, *this), _st_term_ack(sim, *this),
+    _st_terminate(sim, *this), _st_terminated(sim, *this), _st_fail(sim, *this),
+    _st_failed(sim, *this)
+{
+    // set initial state
+    set_state(_st_init);
+}
+
+
+scd_cont_slave_wrapper::~scd_cont_slave_wrapper()
+{
+    if (_socket != NULL)
+        delete _socket;
+}
+
+
+const std::string& scd_cont_slave_wrapper::get_name() const { return _name; }
+
+
+void scd_cont_slave_wrapper::connect(scd_socket* sock)
+{
+    if (!_is_connected)
+    {
+        _socket = sock;
+        _writer.set_socket(*_socket);
+        _reader.set_socket(*_socket);
+        _is_connected = true;
+        scd_info("slave \"" + _name + "\" connected");
+        static_cast<scd_stsw_base*>(_state)->set_connected();
+    }
+    else
+    {
+        scd_warn("slave " + _name + " has already been connected");
+        delete sock;
+    }
+} // connect()
+
+
+void scd_cont_slave_wrapper::send_command(scd_command* cmd)
+{
+    // register write event if not registered
+    if (!_writer.is_writing() && _is_connected && _socket->is_valid())
+        _sim.get_poller().set_ev(*this, SOCK_EV_WRITE | SOCK_EV_READ
+                | SOCK_EV_CLOSE);
+
+    // queue command to be written
+    _writer.queue_command(cmd);
+}
+
+
+bool scd_cont_slave_wrapper::is_sending() const
+{
+    return _writer.is_writing() && _is_connected && _socket->is_valid();
+}
+
+
+void scd_cont_slave_wrapper::close() 
+{
+    if (_is_connected)
+        _socket->close();
+}
+
+
+void scd_cont_slave_wrapper::handle_sock_ev(sock_ev events)
+{
+    scd_stsw_base& state = *static_cast<scd_stsw_base*>(_state);
+
+    if (events & SOCK_EV_CLOSE)
+    {
+        _socket->close();
+        scd_error("connection to slave \"" + _name + "\" lost");
+        state.set_failed();
+        return;
+    }
+
+    if (events & SOCK_EV_READ)
+    {
+        _reader.read();
+     
+        if (!_socket->is_valid())
+        {
+            // connection closed
+            scd_error("connection to slave \"" + _name + "\" lost");
+            state.set_failed();
+            return;
+        }
+
+        if (!_reader.is_reading() && !_reader.has_command())
+        {
+            // received an illegal command
+            scd_error("received illegal command");
+            state.set_fail();
+            return;
+        }
+
+        if (_reader.has_command())
+        {
+            scd_command* cmd = _reader.get_command();
+            _process_cmd(*cmd);
+            delete cmd;
+        }
+
+    } // end read event
+
+    if (events & SOCK_EV_WRITE)
+    {
+        _writer.write();
+
+        if (!_writer.is_writing())
+        {
+            // done sending commands
+            _sim.get_poller().set_ev(*this, SOCK_EV_READ | SOCK_EV_CLOSE);
+        }
+
+        if (!_socket->is_valid())
+        {
+            scd_error("connection to slave \"" + _name + "\" lost");
+            state.set_failed();
+            return;
+        }
+    } // end write event
+
+    
+} // handle_sock_ev()
+
+
+const scd_socket& scd_cont_slave_wrapper::get_sock() { return *_socket; }
+
+
+void scd_cont_slave_wrapper::_process_cmd(const scd_command& cmd)
+{
+    if (cmd.get_type() != SCD_CM_CONTROL)
+    {
+        scd_warn("received non-control command");
+        return;
+    }
+
+    scd_stsw_base* state = static_cast<scd_stsw_base*>(_state);
+    
+    switch(cmd.get_subtype())
+    {
+    case SCD_CM_BUSY:
+        state->set_busy();
+        break;
+    case SCD_CM_IDLE:
+        state->set_idle(cmd.get_time());
+        break;
+    case SCD_CM_DONE:
+        state->set_done();
+        break;
+    case SCD_CM_TIME_NACK:
+        state->recv_time_nack();
+        break;
+    case SCD_CM_TIME_ACK:
+        state->recv_time_ack();
+        break;
+    case SCD_CM_TERM_NACK:
+        state->recv_term_nack();
+        break;
+    case SCD_CM_TERM_ACK:
+        state->recv_term_ack();
+        break;
+    case SCD_CM_FAILED:
+        scd_error("slave \"" + _name + "\" failed");
+        state->set_failed();
+        break;
+    default:
+        scd_warn("received unknown command");
+        break;
+    }
+} // _process_cmd()