Wiselib
|
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