Wiselib
wiselib.testing/external_interface/pc/com_isense_radio.h
Go to the documentation of this file.
00001 // vim: set noexpandtab ts=4 sw=4:
00002 
00003 #ifndef COM_RADIO_H
00004 #define COM_RADIO_H
00005 
00006 #include <cassert>
00007 
00008 #include <iostream>
00009 #include <stdio.h>
00010 #include <signal.h>
00011 #include <pthread.h>
00012 
00013 #include "util/base_classes/extended_radio_base.h"
00014 #include "util/base_classes/base_extended_data.h"
00015 #include "util/delegates/delegate.hpp"
00016 #include "external_interface/pc/com_isense_packet.h"
00017 #include "com_isense_txpower.h"
00018 
00019 #include "config.h"
00020 
00021 typedef uint16_t pc_node_id_t;
00022 
00023 namespace wiselib {
00024    template<
00025       typename OsModel_P,
00026       typename ComUart_P,
00027       typename ExtendedData_P = BaseExtendedData<OsModel_P>
00028    >
00029    class ComISenseRadioModel : public ExtendedRadioBase
00030    <
00031       OsModel_P,
00032       pc_node_id_t,
00033       typename OsModel_P::size_t,
00034       typename OsModel_P::block_data_t,
00035       RADIO_BASE_MAX_RECEIVERS,
00036       ExtendedData_P
00037    >
00038    {
00039       public:
00040          typedef ExtendedData_P ExtendedData;
00041          typedef OsModel_P OsModel;
00042          typedef ComUart_P ComUart;
00043          typedef pc_node_id_t node_id_t;
00044          typedef typename OsModel_P::block_data_t block_data_t;
00045          typedef typename OsModel_P::size_t size_t;
00046          typedef uint8_t message_id_t;
00047 //          typedef delegate3<void, uint16_t, uint8_t, uint8_t*> radio_delegate_t;
00048          typedef ComISensePacket<OsModel> packet_t;
00049          typedef ComISenseRadioModel<OsModel, ComUart, ExtendedData> self_type;
00050          typedef self_type* self_pointer_t;
00051          typedef ComIsenseTxPower<OsModel> TxPower;
00052 
00053          enum SpecialNodeIds {
00054             BROADCAST_ADDRESS = 0xffff,
00055             NULL_NODE_ID = 0
00056          };
00057 
00058          enum Restrictions {
00059             MAX_MESSAGE_LENGTH = 116
00060          };
00061 
00062          ComISenseRadioModel();
00063          ComISenseRadioModel(typename OsModel::Os& os);
00064 
00065          void init(ComUart& uart);
00066          void init();
00067          void destruct();
00068 
00069          void enable_radio();
00070          void disable_radio();
00071 
00072          node_id_t id();
00073          ComUart& uart() { return *uart_; }
00074 
00075          void set_power( TxPower tx_power );
00076 
00077          TxPower power();
00078 
00079          int send(node_id_t, size_t, block_data_t*, int8_t tx_power=1);
00080 
00081          void uart_receive(typename ComUart::size_t, typename ComUart::block_data_t*);
00082 
00083       private:
00084          enum { DLE = 0x10, STX = 0x02, ETX = 0x03 };
00085 
00087          void send_uart(uint8_t);
00088          int write_packet(packet_t&);
00089 
00090          void interpret_uart_packet();
00091 
00092          ComUart *uart_;
00093          node_id_t id_;
00094          volatile bool id_valid_;
00095 
00096          volatile bool sending_;
00097 
00098          volatile bool dle_;
00099          volatile bool in_packet_;
00100          vector_static<OsModel, uint8_t, 256> receiving_;
00101          volatile bool busy_waiting_for_power_;
00102          TxPower tx_power_;
00103    };
00104 
00105    template<typename OsModel_P, typename ComUart_P, typename ExtendedData_P>
00106    ComISenseRadioModel<OsModel_P, ComUart_P, ExtendedData_P>::
00107 	ComISenseRadioModel() {
00108       id_valid_ = false;
00109    }
00110 
00111    template<typename OsModel_P, typename ComUart_P, typename ExtendedData_P>
00112    ComISenseRadioModel<OsModel_P, ComUart_P, ExtendedData_P>::
00113 	ComISenseRadioModel(typename OsModel::Os&) {
00114       id_valid_ = false;
00115    }
00116 
00117    template<typename OsModel_P, typename ComUart_P, typename ExtendedData_P>
00118    void ComISenseRadioModel<OsModel_P, ComUart_P, ExtendedData_P>::
00119 	init(ComUart& uart) {
00120       uart_ = &uart;
00121       assert(uart_);
00122       init();
00123    }
00124 
00125    template<typename OsModel_P, typename ComUart_P, typename ExtendedData_P>
00126    void ComISenseRadioModel<OsModel_P, ComUart_P, ExtendedData_P>::
00127 	init() {
00128       assert(uart_);
00129       id_valid_ = false;
00130 
00131       dle_ = false;
00132       in_packet_ = false;
00133       receiving_.clear();
00134 
00135       uart_->template reg_read_callback<
00136          ComISenseRadioModel,
00137          &ComISenseRadioModel::uart_receive
00138       >(this);
00139    }
00140 
00141    template<typename OsModel_P, typename ComUart_P, typename ExtendedData_P>
00142    void ComISenseRadioModel<OsModel_P, ComUart_P, ExtendedData_P>::
00143 	enable_radio() {
00144       uart_->enable_serial_comm();
00145 
00146       sending_ = false;
00147 
00148       packet_t p(packet_t::SUB_RADIO_GET_ADDRESS);
00149       write_packet(p);
00150    }
00151 
00152    template<typename OsModel_P, typename ComUart_P, typename ExtendedData_P>
00153    void ComISenseRadioModel<OsModel_P, ComUart_P, ExtendedData_P>::
00154 	disable_radio() {
00155    }
00156 
00157    template<typename OsModel_P, typename ComUart_P, typename ExtendedData_P>
00158    typename ComISenseRadioModel<OsModel_P, ComUart_P, ExtendedData_P>::node_id_t ComISenseRadioModel<OsModel_P, ComUart_P, ExtendedData_P>::
00159 	id() {
00160       if( !id_valid_ )
00161       {
00162          packet_t p(packet_t::SUB_RADIO_GET_ADDRESS);
00163          write_packet(p);
00164          // I know active waiting sucks, but probably requiring
00165          // a clock/timer just for this would suck more
00166          while(!id_valid_) {}
00167       }
00168 
00169       return id_;
00170    }
00171 
00172    /* Sets the transmission power. Allowed values are -30, -24, -18, -12, -6, and 0,
00173     * where -30 is the lowest and 0 is the highest transmission power.
00174     */
00175    template<typename OsModel_P, typename ComUart_P, typename ExtendedData_P>
00176    void ComISenseRadioModel<OsModel_P, ComUart_P, ExtendedData_P>::
00177 	set_power( TxPower tx_power ){
00178       packet_t p( packet_t::SUB_NONE );
00179 
00180       p.push_header( packet_t::SUB_SET_TX_POWER );
00181       p.push_header( -tx_power.to_dB() );
00182 
00183       p.set_data( 0, 0 );
00184 
00185       write_packet(p);
00186    }
00187 
00188    template<typename OsModel_P, typename ComUart_P, typename ExtendedData_P>
00189    typename ComISenseRadioModel<OsModel_P, ComUart_P, ExtendedData_P>::TxPower ComISenseRadioModel<OsModel_P, ComUart_P, ExtendedData_P>::
00190 	power() {
00191       busy_waiting_for_power_ = true;
00192       packet_t p(packet_t::SUB_GET_TX_POWER);
00193       write_packet(p);
00194       // I know active waiting sucks, but probably requiring
00195       // a clock/timer just for this would suck more
00196       while(busy_waiting_for_power_) {}
00197 
00198       return tx_power_;
00199    }
00200 
00201    /* The parameter tx_power gives the transmission power. Allowed values are -30, -24, -18, -12, -6, 0 and 1
00202     * where -30 is the lowest and 0 is the highest transmission power. 1 means that the transmission power is not changed.
00203     * Any other value is changed to 1.
00204     */
00205    template<typename OsModel_P, typename ComUart_P, typename ExtendedData_P>
00206    int ComISenseRadioModel<OsModel_P, ComUart_P, ExtendedData_P>::
00207 	send( node_id_t destination, size_t size, block_data_t* data, int8_t tx_power /*= 1*/) {
00208       if( ( tx_power != -30 ) && ( tx_power != -24 ) && ( tx_power != -18 ) &&
00209          ( tx_power != -12 ) && ( tx_power != -6 ) && ( tx_power != 0 ) && ( tx_power != 1 ) )
00210       {
00211          tx_power = 1;
00212       }
00213 
00214       if( tx_power == 1 )
00215          tx_power = -1;
00216 
00217       packet_t p(packet_t::SUB_NONE);
00218 
00219       p.push_header(packet_t::SUB_RADIO_OUT);
00220       p.push_header(-tx_power);
00221       p.push_header16(destination);
00222 
00223       p.set_data(size, data);
00224 
00225       return write_packet(p);
00226    }
00227 
00228    // private:
00229 
00230    template<typename OsModel_P, typename ComUart_P, typename ExtendedData_P>
00231    void ComISenseRadioModel<OsModel_P, ComUart_P, ExtendedData_P>::
00232 	send_uart(uint8_t byte) {
00233       uart_->write(1, reinterpret_cast<char*>(&byte));
00234    }
00235 
00236    template<typename OsModel_P, typename ComUart_P, typename ExtendedData_P>
00237    int ComISenseRadioModel<OsModel_P, ComUart_P, ExtendedData_P>::
00238    write_packet(packet_t& p) {
00239       // Block SIGALRM to avoid interrupting call of timer_handler.
00240       sigset_t signal_set, old_signal_set;
00241       if ( ( sigemptyset( &signal_set ) == -1 ) ||
00242             ( sigaddset( &signal_set, SIGALRM ) == -1 ) ||
00243             pthread_sigmask( SIG_BLOCK, &signal_set, &old_signal_set ) )
00244       {
00245          perror( "Failed to block SIGALRM" );
00246       }
00247 
00248       send_uart(DLE);
00249       send_uart(STX);
00250 
00251       /*
00252       for(size_t i=0; i<p.header_size(); i++) {
00253          std::cout << "header[" << (int)i << "]=" << (int)p.header()[i] << "\n";
00254       }
00255       for(size_t i=0; i<p.data_size(); i++) {
00256          std::cout << "data[" << (int)i << "]=" << (int)p.data()[i] << "\n";
00257       }
00258       */
00259 
00260       for(size_t i=0; i<p.header_size(); i++) {
00261          //DLE characters must be sent twice.
00262          if( (uint8_t)p.header()[i] == DLE )
00263             send_uart( DLE );
00264 
00265          send_uart( p.header()[i] );
00266       }
00267       for(size_t i=0; i<p.data_size(); i++) {
00268          //DLE characters must be sent twice.
00269          if( (uint8_t)p.data()[i] == DLE )
00270             send_uart( DLE );
00271 
00272          send_uart( p.data()[i] );
00273       }
00274 
00275       send_uart(DLE);
00276       send_uart(ETX);
00277 
00278       // Unblock SIGALRM.
00279       if( sigismember( &old_signal_set, SIGALRM ) == 0 )
00280       {
00281          if ( ( sigemptyset( &signal_set ) == -1 ) ||
00282                ( sigaddset( &signal_set, SIGALRM ) == -1 ) ||
00283                pthread_sigmask( SIG_UNBLOCK, &signal_set, 0 ) )
00284          {
00285             perror( "Failed to unblock SIGALRM" );
00286          }
00287       }
00288 
00289       return OsModel::SUCCESS;
00290    }
00291 
00292    template<typename OsModel_P, typename ComUart_P, typename ExtendedData_P>
00293    void ComISenseRadioModel<OsModel_P, ComUart_P, ExtendedData_P>::
00294 	uart_receive(
00295          typename ComUart::size_t size,
00296          typename ComUart::block_data_t* data
00297    ) {
00298       //std::cout << "isense uart_receive " << size << " bytes\n";
00299 
00300       for(size_t i = 0; i<size; i++) {
00301          /*std::cout << std::hex << (int)data[i] << " ";
00302          if( ( data[i] >= 32 ) && ( data[i] < 127 ) )
00303             std::cout << "(" << data[i] << ") ";*/
00304          if( !dle_ ) {
00305             if( data[i] == DLE ) {
00306                dle_ = true;
00307             } else {
00308                if( in_packet_ ) {
00309                   receiving_.push_back( data[i] );
00310                } else {
00311                   std::cout << "Found data outside of packet-frame." << std::endl;
00312                }
00313             }
00314          } else {
00315             dle_ = false;
00316             if( data[i] == DLE ) {
00317                if( in_packet_ ) {
00318                   receiving_.push_back( DLE );
00319                } else {
00320                   std::cout << "Found data outside of packet-frame." << std::endl;
00321                }
00322             } else if(data[i] == STX ) {
00323                if( !in_packet_ ) {
00324                   if( receiving_.size() > 0 ) {
00325                      std::cout << "Threw away " << receiving_.size() << " bytes of data from uart:\n";
00326                      for( size_t j=0; j< receiving_.size(); j++ )
00327                         std:: cout << std::hex << (int)receiving_[j] << " ";
00328                      std::cout << std::endl;
00329                   }
00330                } else {
00331                   std::cout << "Found DLE STX while in packet." << std::endl;
00332                }
00333 
00334                receiving_.clear();
00335                in_packet_ = true;
00336             } else if( data[i] == ETX ) {
00337                if( in_packet_ ) {
00338                   interpret_uart_packet();
00339                } else {
00340                   std::cout << "Found DLE ETX outside of packet." << std::endl;
00341                }
00342 
00343                receiving_.clear();
00344                in_packet_ = false;
00345             } else {
00346                std::cout << "Found unsupported byte after DLE." << std::endl;
00347             }
00348          }
00349       }
00350    }
00351 
00352    template<typename OsModel_P, typename ComUart_P, typename ExtendedData_P>
00353    void ComISenseRadioModel<OsModel_P, ComUart_P, ExtendedData_P>::
00354 	interpret_uart_packet() {
00355       //std::cout << "interpreting packet of size " << receiving_.size() << "\n";
00356 
00357       node_id_t sender;
00358 
00359       if(receiving_[0] == packet_t::MESSAGE_TYPE_CUSTOM_OUT) {
00360          switch(receiving_[1]) {
00361             case packet_t::SUB_RADIO_ADDRESS: {
00362                //assert(receiving_.size() == 4);
00363                if(receiving_.size() < 5)
00364                   return;
00365                id_ = receiving_[3] << 8 | receiving_[4];
00366                id_valid_ = true;
00367                //std::cout << "--- iSense node address: 0x" << std::hex << id_ << std::dec << "\n";
00368             } break;
00369 
00370             case packet_t::SUB_RADIO_IN: {
00371                //assert(receiving_.size() > 4);
00372                if(receiving_.size() <= 17)
00373                   return;
00374                uint16_t signal_strength = receiving_[7] << 8 | receiving_[8];
00375                ExtendedData ex;
00376                ex.set_link_metric( 255 - signal_strength );
00377                sender = receiving_[3] << 8 | receiving_[4];
00378                notify_receivers( sender, receiving_.size() - 17, receiving_.data() + 17, ex );
00379             } break;
00380 
00381             case packet_t::SUB_TX_POWER: {
00382                if( receiving_.size() != 3 )
00383                   return;
00384                tx_power_ = TxPower::from_dB( -receiving_[2] );
00385                busy_waiting_for_power_ = false;
00386             } break;
00387 
00388             default:
00389                break;
00390          } // switch
00391       } // if CUSTOM_IN1
00392       else if( receiving_[0] == packet_t::MESSAGE_TYPE_LOG ) {
00393          std::cout << "iSense-node: ";
00394          for( size_t i=2; i<receiving_.size(); i++ ) {
00395             std::cout << (char)receiving_[i];
00396          }
00397          std::cout << std::endl;
00398       } else {
00399          std::cout << "unexpected msg type " << (char)receiving_[0] << " (" << (int)receiving_[0] << ")\n";
00400       }
00401    } // interpret_uart_packet
00402 }
00403 
00404 #endif // COM_RADIO_H
00405 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines