00001 #include <canopen_master/canopen.h> 00002 #include <canopen_master/master.h> 00003 #include <boost/make_shared.hpp> 00004 #include <iostream> 00005 00006 #include <socketcan_interface/dispatcher.h> 00007 #include <boost/unordered_set.hpp> 00008 #include <socketcan_interface/socketcan.h> 00009 #include <socketcan_interface/threading.h> 00010 00011 #include <boost/thread.hpp> 00012 00013 using namespace can; 00014 using namespace canopen; 00015 00016 class ElmoNode: public Node 00017 { 00018 static boost::shared_ptr<canopen::ObjectDict> make_dict(){ 00019 canopen::DeviceInfo info; 00020 info.nr_of_rx_pdo = 0; 00021 info.nr_of_tx_pdo = 0; 00022 00023 boost::shared_ptr<canopen::ObjectDict> dict = boost::make_shared<canopen::ObjectDict>(info); 00024 00025 dict->insert(true, boost::make_shared<const canopen::ObjectDict::Entry>(0x1023, 1, ObjectDict::DEFTYPE_OCTET_STRING, "Command", false, true, false)); 00026 dict->insert(true, boost::make_shared<const canopen::ObjectDict::Entry>(0x1023, 2, ObjectDict::DEFTYPE_UNSIGNED8, "Status", true, false, false)); 00027 dict->insert(true, boost::make_shared<const canopen::ObjectDict::Entry>(0x1023, 3, ObjectDict::DEFTYPE_OCTET_STRING, "Reply", true, false, false)); 00028 00029 00030 dict->insert(false, boost::make_shared<const canopen::ObjectDict::Entry>(ObjectDict::VAR, 0x1024, ObjectDict::DEFTYPE_UNSIGNED8, "OS command mode", false, true, false)); 00031 00032 dict->insert(false, boost::make_shared<const canopen::ObjectDict::Entry>(ObjectDict::VAR, 0x1001, ObjectDict::DEFTYPE_UNSIGNED8, "error register", true, false, false)); 00033 00034 dict->insert(false, boost::make_shared<const canopen::ObjectDict::Entry>(ObjectDict::VAR, 0x1017, ObjectDict::DEFTYPE_UNSIGNED16, "producer heartbeat", true, true, false, HoldAny((uint16_t)0))); 00035 00036 return dict; 00037 } 00038 00039 ObjectStorage::Entry<canopen::ObjectStorage::DataType<ObjectDict::DEFTYPE_OCTET_STRING>::type > command_; 00040 ObjectStorage::Entry<canopen::ObjectStorage::DataType<ObjectDict::DEFTYPE_UNSIGNED8>::type > status_; 00041 ObjectStorage::Entry<canopen::ObjectStorage::DataType<ObjectDict::DEFTYPE_OCTET_STRING>::type > reply_; 00042 00043 ObjectStorage::Entry<canopen::ObjectStorage::DataType<ObjectDict::DEFTYPE_UNSIGNED8>::type > mode_; 00044 00045 template<typename T> bool try_set(T & entry, const typename T::type &value){ 00046 try{ 00047 entry.set(value); 00048 } 00049 catch(...){ 00050 return false; 00051 } 00052 return true; 00053 } 00054 public: 00055 00056 ElmoNode(boost::shared_ptr<can::CommInterface> interface, const uint8_t &id) : Node (interface, make_dict(), id){ 00057 getStorage()->entry(command_, 0x1023, 1); 00058 getStorage()->entry(status_, 0x1023, 2); 00059 getStorage()->entry(reply_, 0x1023, 3); 00060 00061 getStorage()->entry(mode_, 0x1024); 00062 } 00063 00064 uint8_t send_command(const std::string &s){ 00065 if(!try_set(command_, String(s))) return 0; 00066 00067 uint8_t status; 00068 00069 do{ 00070 status = status_.get(); 00071 }while(status == 255); 00072 00073 return status; 00074 } 00075 void get_response(std::string &s){ 00076 String res; 00077 try{ 00078 res = reply_.get(); 00079 s = (const std::string&) res; 00080 } 00081 catch(const TimeoutException&){ 00082 s = "<TIMEOUT>"; 00083 } 00084 } 00085 00086 }; 00087 00088 00089 00090 boost::shared_ptr<ThreadedSocketCANInterface> driver; 00091 boost::shared_ptr<ElmoNode> node; 00092 StateInterface::StateListener::Ptr state_printer; 00093 00094 void print_state(const State &s){ 00095 boost::shared_ptr<ThreadedSocketCANInterface> d = driver; 00096 std::string msg; 00097 if(!s.error_code && !s.internal_error) return; 00098 00099 if(d && !d->translateError(s.internal_error, msg)) msg = "Undefined"; 00100 std::cerr << "device error: " << s.error_code << " internal_error: " << s.internal_error << " (" << msg << ")" << std::endl; 00101 } 00102 00103 void shutdown(boost::shared_ptr<ThreadedSocketCANInterface> &driver, boost::shared_ptr<ElmoNode> &node, int code){ 00104 state_printer.reset(); 00105 00106 LayerStatus s; 00107 if(node) node->shutdown(s); 00108 if(driver) driver->shutdown(); 00109 exit(code); 00110 } 00111 00112 void sigint_handler (int param) 00113 { 00114 shutdown(driver, node, param); 00115 } 00116 00117 int main(int argc, char *argv[]){ 00118 00119 if(argc <= 2){ 00120 std::cerr << "usage: " << argv[0] << " device node_id [< INPUT] [> OUTPUT]" << std::endl; 00121 return -1; 00122 } 00123 00124 bool tty = isatty(fileno(stdin)); 00125 00126 uint8_t nodeid = atoi(argv[2]); 00127 00128 signal(SIGINT, sigint_handler); 00129 00130 00131 driver = boost::make_shared<ThreadedSocketCANInterface> (); 00132 state_printer = driver->createStateListener(print_state); 00133 00134 if(!driver->init(argv[1],0)){ 00135 std::cerr << "init failed" << std::endl; 00136 return -1; 00137 } 00138 00139 sleep(1.0); 00140 00141 node = boost::make_shared<ElmoNode>(driver, nodeid); 00142 00143 LayerStatus status; 00144 try{ 00145 node->init(status); 00146 if(!status.bounded<LayerStatus::Warn>()){ 00147 std::cerr << status.reason() << std::endl; 00148 shutdown(driver,node,-1); 00149 } 00150 } 00151 catch( const canopen::Exception &e){ 00152 std::cerr << boost::diagnostic_information(e) << std::endl; 00153 shutdown(driver,node,-1); 00154 } 00155 00156 std::string res; 00157 std::string line; 00158 00159 while(std::cin.good()){ 00160 if(tty) std::cout << "> "; 00161 std::getline (std::cin, line); 00162 00163 if(line.empty()) continue; 00164 00165 if(!tty) std::cout << line << ": "; 00166 00167 uint8_t status = node->send_command(line); 00168 if(status){ 00169 node->get_response(res); 00170 std::cout << (status == 1 ? res : "<ERROR>") << std::endl; 00171 }else{ 00172 std::cout << "ERROR!"; 00173 break; 00174 } 00175 } 00176 00177 shutdown(driver,node,0); 00178 00179 return 0; 00180 }