====== Example code ====== ===== CAN communication with control boards ===== The applications running in the embedded Linux environment can communicate with the IO boards through the CAN bus protocol. The high level protocol is a reduced version of the CANopen stack. Here is how to write a Object Dictionary entry: #include #include #include #include #include #include #include #include #include #include #include /** * \brief Initializes a raw socket for CAN communication * \param ifname the interface, typically can0 */ int init_can(const char * ifname) { int s; struct sockaddr_can addr; struct ifreq ifr; if((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { perror("Error while opening socket"); return -1; } strcpy(ifr.ifr_name, ifname); ioctl(s, SIOCGIFINDEX, &ifr); addr.can_family = AF_CAN; addr.can_ifindex = ifr.ifr_ifindex; printf("%s at index %d\n", ifname, ifr.ifr_ifindex); if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("Error in socket bind"); return -2; } return s; } /** * \brief Writes OD entry * \param s socket where to write to * \param idx OD index * \param subidx OD subindex * \param val value to write */ int od_write(int s, uint16_t idx, uint8_t subidx, int32_t val) { struct can_frame frame; frame.can_id = 0x600; frame.can_dlc = 8; frame.data[0] = 0x23; frame.data[1] = idx&0xFF; frame.data[2] = ( idx >> 8 ) & 0xFF ; frame.data[3] = subidx ; frame.data[4] = ( val & 0xFF); frame.data[5] = ( ( val >> 8 ) & 0xFF); frame.data[6] = ( ( val >> 16 ) & 0xFF); frame.data[7] = ( ( val >> 24 ) & 0xFF); write(s, &frame, sizeof(struct can_frame)); return 0; } ===== A simple UObject to control a motor ===== #ifndef UQUIMMOTOR_HPP__ #define UQUIMMOTOR_HPP__ // Include the UObject declarations. # include class UQuimMotor : public urbi::UObject { public: /** * \brief C++ contructor. * * \param name name given to the instance */ UQuimMotor(const std::string& name); /** * \brief Urbi constructor * * \param motor_id * \return 0 on success */ int init(int motor_id); /** * \brief Function notified when the speed is changed. * \param v the UVar being modified * \return 0 on success */ int speed_set(urbi::UVar& v); private: urbi::UVar speed; int motorId_m ; int canSocket_m; }; #endif #include "UQuimMotor.hpp" #include "od_write_master.h" #include // Register the UMachine UObject in the Urbi world. UStart(UQuimMotor); // Bouncing the name to the UObject constructor is mandatory. UQuimMotor::UQuimMotor(const std::string& name) : urbi::UObject(name), motorId_m(0) { // Register the Urbi constructor. This is the only mandatory // part of the C++ constructor. UBindFunction(UQuimMotor, init); } int UQuimMotor::init(int motor_id) { if (! (motor_id == 1 || motor_id == 2) ) { printf("Invalid motor_id\r\n"); return 1; } motorId_m = motor_id ; canSocket_m = init_can("can0"); if (canSocket_m < 0) { printf("Failed to init CAN...\r\n"); return 1; } // Bind the UVars before using them. UBindVar(UQuimMotor, speed); // Request that speed_set be invoked each time speed is changed. UNotifyChange(speed, &UQuimMotor::speed_set); // Success. return 0; } int UQuimMotor::speed_set(urbi::UVar& v) { // Speed entry in QuimMotor entry is at index 0x60FF // subidx indicates which motor to set od_write(canSocket_m, 0x60FF, motorId_m, int(v)); return 0 ; }