pic_packet.c File Reference

Include dependency graph for pic_packet.c:

Data Structures

union  rf_packet
struct  seen_packet
struct  sending_item

Defines

#define PKT_FLAG_DELETED   0xff

Functions

void pkt_calc_check_byte (rf_packet *packet)
uns8 pkt_check_check_byte (rf_packet *packet)
void pkt_init (uns16 my_addr, uns16 last_sent_id)
 Initialise packet delivery system.
uns8 pkt_print_packet (rf_packet *my_packet)
uns8 pkt_process_rf_data (uns8 *data_in)
 Process received RF data.
void pkt_process_tx_queue ()
 Handle queued items.
uns8 pkt_queue_packet (rf_packet *packet, uns8 resend)
uns8 pkt_seen (uns16 pkt_id, uns16 source_addr)
void pkt_send_packet (rf_packet *packet)
uns8 pkt_send_payload (uns16 dest_addr, uns8 *payload, uns8 resend)
 Send a payload via the packet delivery system.

Variables

uns16 pkt_my_addr = 0x66
uns16 pkt_my_next_pkt_id = 0
static seen_packet pkt_seen_list [PKT_SEEN_LIST_SIZE]
uns8 pkt_seen_list_last = 0
static sending_item pkt_tx_queue [PKT_TX_QUEUE_SIZE]

Define Documentation

#define PKT_FLAG_DELETED   0xff

Function Documentation

void pkt_calc_check_byte ( rf_packet packet  ) 

00093                                             {
00094     
00095     uns8 calc, count;
00096 
00097     calc = 0;
00098     for (count = 0; count < PKT_PACKET_SIZE -1; count++) { // -1 since we don't want to include the check digit
00099         calc ^= packet->a[count];
00100     }
00101     packet->d.check_byte = calc;
00102 }

Here is the caller graph for this function:

uns8 pkt_check_check_byte ( rf_packet packet  ) 

00104                                              {
00105     
00106     uns8 calc, count;
00107 
00108     calc = 0;
00109     for (count = 0; count < PKT_PACKET_SIZE -1; count++) { // -1 since we don't want to include the check digit
00110         calc ^= packet->a[count];
00111     }
00112 
00113     if (calc == packet->d.check_byte) 
00114         return 1;
00115      else 
00116         return 0;
00117         
00118 }    

Here is the caller graph for this function:

void pkt_init ( uns16  my_addr,
uns16  last_sent_pkt_id 
)

Initialise the packet delivery system ready for use. This routine clears the transmit queue and seen queue. If you don't store the last_sent_pkt_id (eg, in EEPROM) then set this to 0.

Parameters:
my_addr The address of this system
last_sent_pkt_id The last pkt_id used by this system.

00423                                                  {
00424     // go through tx queue and set all flags to DELETED 
00425 uns8 count;
00426 uns16 current_tick;
00427 
00428     pkt_my_addr = my_addr;  // store my address
00429     pkt_my_next_pkt_id = last_sent_id + 1;  // get next packet id
00430     for (count = 0; count < PKT_TX_QUEUE_SIZE; count++) {
00431         pkt_tx_queue[count].flag = PKT_FLAG_DELETED;  // deleted
00432     }   
00433 
00434     for (count = 0; count < PKT_SEEN_LIST_SIZE; count++ ) {
00435         pkt_seen_list[count].source_addr = 0xffff;  
00436     }
00437 }   

uns8 pkt_print_packet ( rf_packet my_packet  ) 

00120                                             {
00121     
00122     serial_print_str("[Pkt: s:");
00123     serial_print_int_hex(my_packet->d.source_addr);
00124     serial_print_str(" i:");
00125     serial_print_int_hex(my_packet->d.pkt_id);
00126     serial_print_str(" d:");
00127     serial_print_int_hex(my_packet->d.dest_addr);
00128     serial_print_str(" r1:");
00129     serial_print_int_hex(my_packet->d.r1_addr);
00130     serial_print_str(" r2:");
00131     serial_print_int_hex(my_packet->d.r2_addr);
00132     serial_print_str(" r3:");
00133     serial_print_int_hex(my_packet->d.r3_addr);
00134     serial_print_str(" p:");
00135     for (uns8 count = 0; count < PKT_PAYLOAD_SIZE; count++) {
00136         serial_print_int_hex(my_packet->d.payload[count]);
00137         serial_print_spc();
00138     }   
00139     serial_print_str("] ");
00140 }    

Here is the call graph for this function:

Here is the caller graph for this function:

uns8 pkt_process_rf_data ( uns8 *  data_in  ) 

Call this routine when your RF device has received a chunk of data from somewhere. The packet delivery system will handle everything including acknowledgements and ignoring packets that it has already seen.

Parameters:
pkt_in A pointer to the received data. It is assumed that this will point to PKT_PACKET_SIZE bytes of data.

00174                                         {
00175 
00176 uns8 status = 0;
00177 uns8 count;
00178 uns16 orig_pkt_id;
00179 uns8 ack_payload[PKT_PAYLOAD_SIZE] = { 0xff, 0xff };
00180 sending_item *pitem;
00181 rf_packet packet;
00182     start_crit_sec();
00183     
00184     memcpy(/*dst*/  (void *)&packet, // copy it in
00185            /*src*/  (void *)data_in,
00186            /*len*/  PKT_PACKET_SIZE);
00187     end_crit_sec();
00188 
00189     #ifdef PKT_DEBUG
00190         serial_putc('r');
00191         pkt_print_packet(&packet);
00192     #endif
00193     if (!pkt_check_check_byte(&packet)) {
00194         #ifdef PKT_DEBUG_HIGH
00195             serial_print_str("CF! ");
00196         #endif
00197         return PKT_STATUS_CHECK_FAIL;
00198     }   
00199 
00200     // Am I the dest addr?
00201     if ((packet.d.dest_addr == pkt_my_addr) ||
00202         (packet.d.dest_addr == PKT_BROADCAST_ADDR)) {
00203         status = PKT_STATUS_PKT_IS_FOR_ME;
00204         // It's for me. But is it an ack?
00205         if ((packet.d.payload[0] != 0xff) ||
00206             (packet.d.payload[1] != 0xff)) { // not an ack, so send one     
00207             ack_payload[2] = packet.d.pkt_id & 0xff;
00208             ack_payload[3] = packet.d.pkt_id >> 8;
00209             #ifndef PKT_DEBUG_NO_TRANSMIT
00210                 uns8 send_status = pkt_send_payload(packet.d.source_addr, ack_payload, PKT_FLAG_NO_RESEND);
00211                 #ifdef PKT_DEBUG 
00212                     serial_print_str("ACKst=");
00213                     serial_print_int(send_status);
00214                 #endif
00215             #endif      
00216         } else { // We got an ack!
00217             status = PKT_STATUS_PKT_IS_ACK_FOR_ME;
00218             orig_pkt_id = packet.d.payload[3];
00219             orig_pkt_id <<= 8;
00220             orig_pkt_id += packet.d.payload[2];
00221             for (count = 0; count < PKT_TX_QUEUE_SIZE; count++) { // Search for a packet
00222                 pitem = &pkt_tx_queue[count];
00223                 if ((pitem->flag != PKT_FLAG_DELETED) &&
00224                 (pitem->packet.d.pkt_id == orig_pkt_id)) {
00225                     status = PKT_STATUS_PKT_IS_FACK_FOR_ME;  // Found the ack
00226                     #ifdef PKT_CALLBACK_ON_SEND_SUCCEEDED
00227                         pkt_send_succeeded_callback(pitem->packet.d.dest_addr, pitem->packet.d.pkt_id);
00228                     #endif  
00229                     
00230                     pitem->flag = PKT_FLAG_DELETED;
00231                 }
00232             }           
00233         } // [we got an ack]
00234 
00235         
00236         // If not seen before, then process     
00237         if (!pkt_seen(packet.d.pkt_id, packet.d.source_addr)) {
00238         
00239             // process payload
00240             if ((status != PKT_STATUS_PKT_IS_FACK_FOR_ME) && 
00241                (status != PKT_STATUS_PKT_IS_ACK_FOR_ME)) {
00242                 pkt_payload_rx_callback(packet.d.source_addr, packet.d.pkt_id, packet.d.payload);
00243             }   
00244             // Add to seen list
00245             pkt_seen_list_last++;
00246             if (pkt_seen_list_last == PKT_SEEN_LIST_SIZE) {
00247                 pkt_seen_list_last = 0;
00248             }
00249             pkt_seen_list[pkt_seen_list_last].pkt_id = packet.d.pkt_id;
00250             pkt_seen_list[pkt_seen_list_last].source_addr = packet.d.source_addr;
00251         } else {
00252             status = PKT_STATUS_PKT_FOR_ME_BUT_SEEN;
00253             #ifdef PKT_DEBUG_HIGH
00254                 serial_print_str(" seen ");
00255             #endif  
00256         }   
00257     }       
00258     else
00259     // Is sender + pkt_id seen?
00260     if (pkt_seen(packet.d.pkt_id, packet.d.source_addr)) {
00261         // We've seen this packet before
00262         status = PKT_STATUS_SEEN_BEFORE;    
00263     } else 
00264     // Am I the sender?
00265     if (packet.d.source_addr == pkt_my_addr) {
00266         status = PKT_STATUS_I_AM_SENDER;
00267     } else
00268     // Is the r1_addr = 0xffff, meaning direct send?
00269     if (packet.d.r1_addr == PKT_DIRECT_SEND_ADDR) {
00270         status = PKT_STATUS_DIRECT_SEND;
00271     } else   
00272     // Am I one of the routers?
00273     if ((packet.d.r1_addr == pkt_my_addr) ||
00274         (packet.d.r2_addr == pkt_my_addr) ||
00275         (packet.d.r3_addr == pkt_my_addr)) {
00276         status = PKT_STATUS_PREVIOUS_ROUTED_VIA_ME;
00277     } else 
00278     // Is r3 full?
00279     if (packet.d.r3_addr != 0) {
00280         status = PKT_STATUS_ROUTING_FULL;
00281     } else {  // I need to re-broadcast this packet
00282         status = PKT_STATUS_NEED_TO_REBROADCAST;
00283         // Add me as a router
00284         if (packet.d.r1_addr == 0) {
00285             packet.d.r1_addr = pkt_my_addr;
00286         } else if (packet.d.r2_addr == 0) {
00287             packet.d.r2_addr = pkt_my_addr;
00288         } else { 
00289             packet.d.r3_addr = pkt_my_addr;
00290         }       
00291         // Update check byte now we've changed packet
00292         pkt_calc_check_byte(&packet);
00293         // queue packet no resend
00294         
00295         #ifndef PKT_DEBUG_NO_TRANSMIT
00296             pkt_queue_packet(&packet, PKT_FLAG_NO_RESEND);
00297         #endif
00298         // add to seen list?
00299     } // [I need to re-broadcast this packet]
00300 
00301     return status;
00302 }

Here is the call graph for this function:

void pkt_process_tx_queue (  ) 

Call this routine regularly (as often as possible) in your main loop in order for the packet delivery system to send any queued packets when it is appropriate to do so. It will also remove any packets from the tx queue that have been there too long.

00354                             {
00355 
00356 uns8 count;
00357 uns16 current_tick;
00358 uns8 sent_count;
00359 uns8 flag;
00360 sending_item *item;
00361     
00362     current_tick = tick_get_count();
00363     
00364     for (count = 0; count < PKT_TX_QUEUE_SIZE; count++) { // search for a packet
00365         item = &pkt_tx_queue[count];    // grab item to save code
00366         flag = item->flag;
00367         if (flag != PKT_FLAG_DELETED) { // got something to send
00368             sent_count = item->sent_count;
00369             if (sent_count > PKT_SEND_MAX_TRIES) { // Sent too many times
00370                 item->flag = PKT_FLAG_DELETED; // Delete
00371                 #ifdef PKT_CALLBACK_ON_SEND_FAILED
00372                     pkt_send_failed_callback(item->packet.d.dest_addr, item->packet.d.pkt_id);
00373                 #endif
00374                 #ifdef PKT_DEBUG
00375                     serial_print_str(" SF!\n ");
00376                 #endif
00377             } else if ((sent_count == 0) // Never tried to send 
00378                || (tick_calc_diff(item->tick_sent, current_tick)
00379                      > PKT_RESEND_TICK_DELAY*sent_count + count)) { // Or more than delay time since last try
00380                         // Note slight randomness built in by adding array position (count)
00381                 item->tick_sent = current_tick; // set tick count to current
00382                 //delay_us(pkt_my_addr & 0x07 *30);
00383                 #ifdef PKT_DEBUG_PAYLOAD_SENT
00384                     item->packet.d.payload[7] = sent_count;
00385                     pkt_calc_check_byte((rf_packet*)item);
00386                 #endif
00387                 #ifdef PKT_DEBUG_HIGH
00388                     serial_print_str(" t=");
00389                     serial_print_int(current_tick);
00390                     serial_print_spc();
00391                 #endif  
00392                 pkt_send_packet((rf_packet*)item);  // send it
00393                 #ifdef PKT_CALLBACK_ON_SEND
00394                     pkt_send_callback(item->packet.d.dest_addr, item->packet.d.pkt_id);
00395                 #endif
00396                 
00397                 if (flag != PKT_FLAG_RESEND) {  // no resend?
00398                     item->flag = PKT_FLAG_DELETED;  // then delete
00399                     #ifdef PKT_DEBUG_HIGH
00400                         serial_print_str(" SNR ");
00401                         pkt_print_packet((rf_packet*)item);
00402                     #endif  
00403                     
00404                 } else { // Yes resend
00405                     item->sent_count++;
00406                     #ifdef PKT_DEBUG_HIGH
00407                         serial_print_str("SC ");
00408                         serial_print_int(pkt_tx_queue[count].sent_count);
00409                         serial_print_spc();
00410                     #endif  
00411                     
00412                     // clear direct send, next one goes to everyone!
00413                     if (item->packet.d.r1_addr == 0xffff) {
00414                         item->packet.d.r1_addr = 0;
00415                     }   
00416                 } // [Yes resend]       
00417             } // [Okay to send it]  
00418         }  // [Got something to send]
00419     } // [Search for a packet]
00420 } // 269 + 12

Here is the call graph for this function:

uns8 pkt_queue_packet ( rf_packet packet,
uns8  resend 
)

00145 {
00146 uns8 count, found;
00147     // find slot
00148     found = 0;
00149     for (count = 0; count < PKT_TX_QUEUE_SIZE; count++) {
00150         if (pkt_tx_queue[count].flag == PKT_FLAG_DELETED) {
00151             found = 1;
00152             break;
00153         }
00154     }
00155     if (found) {
00156         #ifdef PKT_DEBUG_HIGH
00157             serial_print_str(" Qin ");
00158             serial_print_int(count);
00159         #endif  
00160         memcpy(/*dst*/  (void *)&pkt_tx_queue[count], // copy it in
00161                /*src*/  (void *)packet,
00162                /*len*/  PKT_PACKET_SIZE);
00163         pkt_tx_queue[count].sent_count = 0;
00164         //  resend = resend 
00165         pkt_tx_queue[count].flag = resend;
00166         return PKT_STATUS_QUEUED;
00167     } else {
00168         return PKT_STATUS_TX_QUEUE_FULL;
00169     }   
00170     
00171 } 

Here is the call graph for this function:

Here is the caller graph for this function:

uns8 pkt_seen ( uns16  pkt_id,
uns16  source_addr 
)

00080                                                {
00081 
00082 uns8 count;
00083 
00084     for (count = 0; count < PKT_SEEN_LIST_SIZE; count++ ) {
00085         if ((pkt_seen_list[count].pkt_id == pkt_id) && 
00086            (pkt_seen_list[count].source_addr == source_addr)) {
00087             return 1;
00088         } // if
00089     } // for
00090     return 0; // didn't find it
00091 }           

Here is the caller graph for this function:

void pkt_send_packet ( rf_packet packet  )  [inline]

00328                                                {
00329 
00330 uns8 tx_buffer[PKT_PACKET_SIZE + 3]; // +3 for RF address (fixed)
00331 uns8 count;
00332 
00333     #ifdef PKT_DEBUG
00334         serial_print_str(" <S>");
00335     #endif    
00336     #ifdef PKT_DEBUG_HIGH
00337         pkt_print_packet(packet);
00338     #endif   
00339     tx_buffer[0] = 0b11100111; // address
00340     tx_buffer[1] = 0b11100111; // address
00341     tx_buffer[2] = 0b11100111; // address
00342     for (count = 0; count < PKT_PACKET_SIZE; count++) {
00343       tx_buffer[count+3] = packet->a[count];
00344     }  
00345     pic_rf_transmit(tx_buffer, PKT_PACKET_SIZE + 3);
00346     //pic_rf_transmit((uns8 *)packet, PKT_PACKET_SIZE);
00347 }

Here is the call graph for this function:

Here is the caller graph for this function:

uns8 pkt_send_payload ( uns16  dest_addr,
uns8 *  payload,
uns8  resend 
)

Use this routine to send a payload of data to the destination address. The payload must point to PKT_PAYLOAD_SIZE bytes of data (as defined in your config.h). The packet will be constructed, setting destination address, sender address (set previously in pkt_init) payload, initial routing directions and the check byte calculated. It will then be placed into the tx queue and will actually be sent next time pkt_process_tx_queue is called.

Parameters:
dest_addr Send payload to this address. Use address of PKT_BROADCAST_ADDR to broadcast to all listening local addresses
pay_load Pointer to PKT_PAYLOAD_SIZE array of bytes
resend Set to PKT_FLAG_RESEND or PKT_FLAG_NO_RESEND

00440                                                                    {
00441 
00442 rf_packet my_packet;
00443 uns8 count;
00444 
00445     #ifdef PKT_DEBUG_HIGH
00446     serial_print_str("\npkt send d:");
00447     serial_print_int(dest_addr);
00448     serial_print_str("s: ");
00449     serial_print_int(pkt_my_addr);
00450     serial_print_str("\n");
00451     #endif
00452     
00453     // build packet
00454     
00455     my_packet.d.source_addr = pkt_my_addr;
00456     my_packet.d.pkt_id = pkt_my_next_pkt_id++;
00457     my_packet.d.dest_addr = dest_addr;
00458     my_packet.d.r1_addr = 0;
00459     if ((dest_addr != PKT_BROADCAST_ADDR) &&
00460          ((payload[0] != 0xff) || (payload[1] != 0xff))) {  // if not broadcast send
00461         my_packet.d.r1_addr = PKT_DIRECT_SEND_ADDR; // for direct send
00462     }
00463     my_packet.d.r2_addr = 0;
00464     my_packet.d.r3_addr = 0;
00465     for (count = 0; count < PKT_PAYLOAD_SIZE; count++) {
00466         my_packet.d.payload[count] = payload[count];
00467     }   
00468     pkt_calc_check_byte(&my_packet);
00469     
00470     #ifdef PKT_DEBUG
00471         serial_print_str(" PS");
00472         pkt_print_packet(&my_packet);
00473     #endif
00474     
00475     // Put it in the queue for sending
00476     
00477     return pkt_queue_packet(&my_packet, resend);
00478 }    

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

uns16 pkt_my_addr = 0x66
uns16 pkt_my_next_pkt_id = 0
seen_packet pkt_seen_list[PKT_SEEN_LIST_SIZE] [static]
sending_item pkt_tx_queue[PKT_TX_QUEUE_SIZE] [static]

Generated on Fri Aug 19 09:07:56 2011 for Pic Pack Library by  doxygen 1.6.1