00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "buttons.h"
00035 #include "gzll_mcu.h"
00036 #include "gzll.h"
00037 #include "hal_clk.h"
00038 #include "lib_display.h"
00039 #include "stdio.h"
00040 #include "string.h"
00041 #include "nordic_common.h"
00042
00043 #include "hal_delay.h"
00044
00045 void assert_handler(uint16_t line, char* file)
00046 {
00047 line = line;
00048 file = file;
00049 }
00050
00051
00052
00053
00054
00058 void app_init(void);
00059
00063 uint8_t buttons_read(void);
00064
00068 bool com_execute(void);
00069
00074 void app_execute(uint8_t buttons);
00075
00081 uint16_t inc_mod(uint16_t dat, uint16_t limit);
00082
00088 uint16_t dec_mod(uint16_t dat, uint16_t limit);
00089
00094 void lcd_update(char * l0, char * l1);
00095
00100 void t2_init(void);
00101
00106 void itoa(uint16_t i, char * a);
00107
00113 void strcpy_nrf(char *dest, char const code *src);
00114
00115
00116
00117
00118
00122 void mm_mode_select(char * lcd_l0, char * lcd_l1, uint8_t buttons);
00123
00127 void mm_test_app_setup(char * lcd_l0, char * lcd_l1, uint8_t buttons);
00128
00132 void mm_gzll_params(char * lcd_l0, char * lcd_l1, uint8_t buttons);
00133
00137 void mm_statistics(char * lcd_l0, char * lcd_l1, uint8_t buttons);
00138
00142 void mm_channel_setup(char * lcd_l0, char * lcd_l1, uint8_t buttons);
00143
00144
00145
00146
00147
00148 typedef enum
00149 {
00150 MM_MODE_SELECT,
00151 MM_TEST_APP_SETUP,
00152 MM_STATISTICS,
00153 MM_GZLL_PARAMS,
00154 MM_CHANNEL_SETUP,
00155 MM_LAST_PAGE
00156 }main_menu_pages_t;
00157
00158 char main_menu_header[][17] =
00159 {
00160 "* Mode select *",
00161 "* Test setup *",
00162 "* Statistics *",
00163 "* Gzll params *",
00164 "* Channel conf *"
00165 };
00166
00167
00168
00169
00170
00171 #define MM_MODE_SELECT_HEADER "Operation:"
00172 #define MM_MODE_SELECT_DEVICE "Device"
00173 #define MM_MODE_SELECT_HOST "Host"
00174 #define DEFAULT_DEVICE_MODE true
00175
00176
00177
00178
00179
00180 typedef enum
00181 {
00182 TX_PACKET_INTERVAL,
00183 TX_PL_LENGTH,
00184 ACK_PL_LENGTH,
00185 TX_PIPE
00186 }app_setup_t;
00187 #define APP_SETUP_SIZE 4
00188
00189 code const char app_setup_menu_header[][17] =
00190 {
00191 "TX interval:",
00192 "TX PL len:",
00193 "ACK TX PL len:",
00194 "TX pipe:"
00195 };
00196
00197 xdata uint16_t app_setup[APP_SETUP_SIZE] =
00198 {
00199 8,
00200 10,
00201 0,
00202 0,
00203 };
00204
00205 code const uint16_t app_setup_maximum[APP_SETUP_SIZE] =
00206 {
00207 0xffff,
00208 GZLL_MAX_FW_PAYLOAD_LENGTH,
00209 GZLL_MAX_ACK_PAYLOAD_LENGTH,
00210 5
00211 };
00212
00213
00214
00215
00216
00217 code const char gzll_param_menu_header[][17] =
00218 {
00219 "DEVICE_MODE:",
00220 "TX_TIMEOUT:",
00221 "TX_ATT..SNC_ON:",
00222 "TX_ATT..SNC_OFF:",
00223 "HOST_MODE:",
00224 "RX_PIPES:",
00225 "RX_TIMEOUT:",
00226 "TX_M1_CYCLE_PER:",
00227 "RX_PERIOD:",
00228 "RX_PERIOD_MOD:",
00229 "RX_CH_HOLD_PER:",
00230 "CRYPT_PIPES:",
00231 "OUTPUT_POWER:",
00232 "PDOWN_IDLE_EN:",
00233 "MAX_SYNC_PERIOD:",
00234 "COL_CH_SW_LIM:",
00235 };
00236
00237 code const char gzll_output_power[][17] =
00238 {
00239 "-18 dBm",
00240 "-12 dBm",
00241 "-6 dBm",
00242 "0 dBm"
00243 };
00244
00245
00246
00247
00248
00249 typedef enum
00250 {
00251 TX_PL_CNT,
00252 TX_TRY_CNT,
00253 AVG_TX_TRIES,
00254 MAX_TX_TRIES,
00255 TX_CH_SWITCHES,
00256 TX_BYTE_CNT,
00257 RX_PL_CNT,
00258 RX_BYTE_CNT
00259 }statistics_t;
00260 #define STATISTICS_SIZE 8
00261
00262 code const char statistics_menu_header[][17] =
00263 {
00264 "TX payloads:",
00265 "TX attempts:",
00266 "Avg TX attempts:",
00267 "Max TX attempts:",
00268 "TX ch switches:",
00269 "TX bytes:",
00270 "RX payloads:",
00271 "RX bytes:",
00272 };
00273
00274 xdata uint32_t statistics[STATISTICS_SIZE] =
00275 {
00276 0,
00277 0,
00278 0,
00279 0,
00280 0,
00281 0,
00282 0,
00283 0
00284 };
00285
00286
00287
00288
00289
00290 #define MESSAGE_RUN_L0 " Running!"
00291 #define MESSAGE_RUN_L1 " "
00292
00293 #define MESSAGE_STOP_L0 " Stopped!"
00294 #define MESSAGE_STOP_L1 " "
00295
00296 #define MESSAGE_STATISTICS_CLR_L0 " Statistics"
00297 #define MESSAGE_STATISTICS_CLR_L1 " cleared!"
00298
00299
00300
00301
00302
00306 void main(void)
00307 {
00308 bool radio_activity;
00309 uint8_t buttons;
00310
00311 mcu_init();
00312
00313 gzll_init();
00314 app_init();
00315 lcd_init();
00316
00317 EA = 1;
00318
00319 app_execute(0);
00320
00321
00322
00323
00324 for(;;)
00325 {
00326 buttons = buttons_read();
00327 radio_activity = com_execute();
00328
00329 if((buttons) || (radio_activity))
00330 {
00331 app_execute(buttons);
00332 }
00333 }
00334 }
00335
00336
00337
00338
00339
00340
00341 xdata bool radio_run = false;
00342
00343
00344 xdata bool device_mode = DEFAULT_DEVICE_MODE;
00345
00346 xdata volatile bool gzll_timer_tick;
00347
00348
00349 xdata uint16_t cnt_1ms = 0;
00350 xdata uint8_t button_db = 0;
00351
00352
00353 #define BUFFER_SIZE 16
00354 char buffer_a[BUFFER_SIZE]= {0};
00355 char buffer_b[BUFFER_SIZE]= {0};
00356
00357
00358
00359
00360
00361 void app_init()
00362 {
00363 t2_init();
00364 }
00365
00366 bool com_execute()
00367 {
00368 bool retval = false;
00369 uint8_t user_data[32];
00370 uint16_t temp;
00371 uint8_t t_length, t_pipe;
00372 gzll_states_t curr_gzll_state;
00373 static gzll_states_t prev_gzll_state = (gzll_states_t)0xff;
00374
00375
00376 if(device_mode)
00377 {
00378
00379 curr_gzll_state = gzll_get_state();
00380
00381 if(curr_gzll_state == GZLL_IDLE)
00382 {
00383
00384 if(prev_gzll_state == GZLL_DEVICE_ACTIVE)
00385 {
00386 retval = true;
00387
00388 if(gzll_tx_success())
00389 {
00390 statistics[TX_PL_CNT]++;
00391 statistics[TX_BYTE_CNT] += app_setup[TX_PL_LENGTH];
00392 temp = gzll_get_tx_attempts();
00393 statistics[TX_TRY_CNT] += temp;
00394 statistics[AVG_TX_TRIES] = (uint16_t)(((float)statistics[TX_TRY_CNT] * 100) / statistics[TX_PL_CNT] );
00395 if(statistics[MAX_TX_TRIES] < temp)
00396 {
00397 statistics[MAX_TX_TRIES] = temp;
00398 }
00399 statistics[TX_CH_SWITCHES] += gzll_get_tx_channel_switches();
00400 }
00401
00402 if(gzll_rx_fifo_read(user_data, &t_length, &t_pipe))
00403 {
00404 statistics[RX_PL_CNT]++;
00405 statistics[RX_BYTE_CNT] += t_length;
00406 }
00407 }
00408
00409 if(radio_run)
00410 {
00411 EA = 0;
00412 if(cnt_1ms >= app_setup[TX_PACKET_INTERVAL] )
00413 {
00414 gzll_timer_tick = false;
00415 cnt_1ms = 0;
00416 EA = 1;
00417
00418 while(!gzll_timer_tick){}
00419 gzll_tx_data(user_data, (uint8_t)app_setup[TX_PL_LENGTH], (uint8_t)app_setup[TX_PIPE]);
00420 curr_gzll_state = GZLL_DEVICE_ACTIVE;
00421 }
00422 EA = 1;
00423 }
00424 prev_gzll_state = curr_gzll_state;
00425 }
00426 }
00427
00428 else
00429 {
00430 if(gzll_rx_fifo_read(user_data, &t_length, &t_pipe))
00431 {
00432 retval = true;
00433 statistics[RX_PL_CNT]++;
00434 statistics[RX_BYTE_CNT] += t_length;
00435
00436 t_length = (uint8_t)app_setup[ACK_PL_LENGTH];
00437 if(t_length != false)
00438 {
00439 if(gzll_ack_payload_write(user_data, t_length, t_pipe))
00440 {
00441 statistics[TX_PL_CNT]++;
00442 statistics[TX_BYTE_CNT] += t_length;
00443 }
00444 }
00445 }
00446 }
00447
00448 return retval;
00449 }
00450
00451 void app_execute(uint8_t buttons)
00452 {
00453 static xdata uint8_t main_menu = 0;
00454 uint8_t lcd_line0[17], lcd_line1[17], i;
00455
00456
00457
00458
00459
00460 if((buttons & (MAIN_MENU_INC | MAIN_MENU_DEC)) != false)
00461 {
00462 if((buttons & MAIN_MENU_INC) != false)
00463 {
00464 main_menu = (uint8_t)inc_mod(main_menu, (uint8_t)MM_LAST_PAGE - 1);
00465 }
00466
00467 if((buttons & MAIN_MENU_DEC) != false)
00468 {
00469 main_menu = (uint8_t)dec_mod(main_menu, (uint8_t)MM_LAST_PAGE - 1);
00470 }
00471 lcd_update(main_menu_header[main_menu], " ");
00472 delay_ms(DELAY_SHORT_MESSAGE);
00473 }
00474
00475 if((buttons & RUN_STOP) != false)
00476 {
00477 if(radio_run)
00478 {
00479 radio_run = false;
00480 gzll_goto_idle();
00481 lcd_update(MESSAGE_STOP_L0, MESSAGE_STOP_L1);
00482 delay_ms(DELAY_SHORT_MESSAGE);
00483 }
00484 else
00485 {
00486 if(!device_mode)
00487 {
00488 gzll_rx_start();
00489 }
00490 radio_run = true;
00491 lcd_update(MESSAGE_RUN_L0, MESSAGE_RUN_L1);
00492 delay_ms(DELAY_SHORT_MESSAGE);
00493 }
00494 }
00495
00496 if((buttons & CLEAR_STATISTICS) != false)
00497 {
00498 lcd_update(MESSAGE_STATISTICS_CLR_L0, MESSAGE_STATISTICS_CLR_L1);
00499 delay_ms(DELAY_SHORT_MESSAGE);
00500
00501 for(i = 0; i < STATISTICS_SIZE; i++)
00502 {
00503 statistics[i] = 0;
00504 }
00505 }
00506
00507
00508
00509
00510
00511 switch(main_menu)
00512 {
00513 case MM_MODE_SELECT:
00514 mm_mode_select((void*)lcd_line0, (void*)lcd_line1, buttons);
00515 break;
00516 case MM_TEST_APP_SETUP:
00517 mm_test_app_setup((void*)lcd_line0, (void*)lcd_line1, buttons);
00518 break;
00519 case MM_GZLL_PARAMS:
00520 mm_gzll_params((void*)lcd_line0, (void*)lcd_line1, buttons);
00521 break;
00522 case MM_STATISTICS:
00523 mm_statistics((void*)lcd_line0, (void*)lcd_line1, buttons);
00524 break;
00525 case MM_CHANNEL_SETUP:
00526 mm_channel_setup((void*)lcd_line0, (void*)lcd_line1, buttons);
00527 break;
00528 default:
00529 ;
00530 }
00531
00532 lcd_update((void*)lcd_line0, (void*)lcd_line1);
00533 }
00534
00535 void lcd_update(char * l0, char * l1)
00536 {
00537 uint8_t n0, n1;
00538 char temp_l0[17], temp_l1[17];
00539
00540 static char curr_l0[17] = {0}, curr_l1[17] = {0};
00541
00542 n0 = (uint8_t)strlen(l0);
00543 n1 = (uint8_t)strlen(l1);
00544
00545 strcpy(temp_l0, l0);
00546 strcpy(temp_l1, l1);
00547
00548
00549
00550 for(; n0 < 16; n0++)
00551 {
00552 temp_l0[n0] = ' ';
00553 }
00554 temp_l0[16] = 0;
00555
00556 for(; n1 < 16; n1++)
00557 {
00558 temp_l1[n1] = ' ';
00559 }
00560 temp_l1[16] = 0;
00561
00562 if(strcmp(curr_l0, temp_l0) != 0)
00563 {
00564 strcpy(curr_l0, temp_l0);
00565 lcd_write_string(curr_l0, 0, 0);
00566 }
00567
00568 if(strcmp(curr_l1, temp_l1) != 0)
00569 {
00570 strcpy(curr_l1, temp_l1);
00571 lcd_write_string(curr_l1, 1, 0);
00572 delay_ms(5);
00573 }
00574 }
00575
00576 void mm_mode_select(char * lcd_l0, char * lcd_l1, uint8_t buttons)
00577 {
00578 if((buttons & VALUE_INC) != false || (buttons & VALUE_DEC) != false)
00579 {
00580 device_mode = !device_mode;
00581 }
00582
00583 strcpy(lcd_l0, MM_MODE_SELECT_HEADER);
00584
00585 if(device_mode)
00586 {
00587 strcpy(lcd_l1, MM_MODE_SELECT_DEVICE);
00588 }
00589 else
00590 {
00591 strcpy(lcd_l1, MM_MODE_SELECT_HOST);
00592 }
00593 }
00594
00595 void mm_test_app_setup(char * lcd_l0, char * lcd_l1, uint8_t buttons)
00596 {
00597 static xdata uint8_t app_setup_page = 0;
00598
00599 if((buttons & SUB_MENU_INC))
00600 {
00601 app_setup_page = (uint8_t)inc_mod(app_setup_page, APP_SETUP_SIZE - 1);
00602 }
00603
00604 if((buttons & SUB_MENU_DEC))
00605 {
00606 app_setup_page = (uint8_t)dec_mod(app_setup_page, APP_SETUP_SIZE - 1);
00607 }
00608
00609 if((buttons & VALUE_INC))
00610 {
00611 app_setup[app_setup_page] = inc_mod(app_setup[app_setup_page], app_setup_maximum[app_setup_page]);
00612 }
00613
00614 if((buttons & VALUE_DEC))
00615 {
00616 app_setup[app_setup_page] = dec_mod(app_setup[app_setup_page], app_setup_maximum[app_setup_page]);
00617 }
00618
00619 strcpy_nrf(lcd_l0, app_setup_menu_header[app_setup_page]);
00620 itoa(app_setup[app_setup_page],buffer_a);
00621 strcpy(lcd_l1, buffer_a);
00622 }
00623
00624 void mm_gzll_params(char * lcd_l0, char * lcd_l1, uint8_t buttons)
00625 {
00626 static xdata uint8_t gzll_param_page = 0;
00627
00628 if((buttons & SUB_MENU_INC))
00629 {
00630 gzll_param_page = (uint8_t)inc_mod((uint8_t)gzll_param_page, GZLL_DYN_PARAM_SIZE - 1);
00631 }
00632
00633 if((buttons & SUB_MENU_DEC))
00634 {
00635 gzll_param_page = (uint8_t)dec_mod(gzll_param_page, GZLL_DYN_PARAM_SIZE - 1);
00636 }
00637
00638 if((buttons & VALUE_INC))
00639 {
00640 gzll_set_param((gzll_dyn_params_t)gzll_param_page, inc_mod(gzll_get_param((gzll_dyn_params_t)gzll_param_page), gzll_get_param_max((gzll_dyn_params_t)gzll_param_page)));
00641 }
00642
00643 if((buttons & VALUE_DEC))
00644 {
00645 gzll_set_param((gzll_dyn_params_t)gzll_param_page, dec_mod(gzll_get_param((gzll_dyn_params_t)gzll_param_page), gzll_get_param_max((gzll_dyn_params_t)gzll_param_page)));
00646 }
00647
00648 strcpy_nrf(lcd_l0, gzll_param_menu_header[gzll_param_page]);
00649 if((gzll_dyn_params_t)gzll_param_page == GZLL_PARAM_OUTPUT_POWER)
00650 {
00651 strcpy_nrf(lcd_l1, gzll_output_power[gzll_get_param((gzll_dyn_params_t)gzll_param_page)]);
00652 }
00653 else
00654 {
00655 itoa(gzll_get_param((gzll_dyn_params_t)gzll_param_page), buffer_a);
00656 strcpy(lcd_l1, buffer_a);
00657 }
00658 }
00659
00660 void mm_statistics(char * lcd_l0, char * lcd_l1, uint8_t buttons)
00661 {
00662 static xdata uint8_t statistics_page = 0;
00663
00664 if((buttons & SUB_MENU_INC))
00665 {
00666 statistics_page = (uint8_t)inc_mod(statistics_page, STATISTICS_SIZE - 1);
00667 }
00668
00669 if((buttons & SUB_MENU_DEC))
00670 {
00671 statistics_page = (uint8_t)dec_mod(statistics_page, STATISTICS_SIZE - 1);
00672 }
00673
00674 strcpy_nrf(lcd_l0, statistics_menu_header[statistics_page]);
00675
00676
00677 if(statistics_page == (uint8_t)AVG_TX_TRIES)
00678 {
00679 itoa(statistics[AVG_TX_TRIES],buffer_a);
00680 buffer_b[0] = buffer_a[0];
00681 buffer_b[1] = '.';
00682 buffer_b[2] = buffer_a[1];
00683 buffer_b[3] = buffer_a[2];
00684 buffer_b[4] = '\0';
00685 strcpy(lcd_l1, buffer_b);
00686 }
00687
00688 else
00689 {
00690 itoa(statistics[statistics_page],buffer_a);
00691 strcpy(lcd_l1,buffer_a);
00692 }
00693 }
00694
00695 void mm_channel_setup(char * lcd_l0, char * lcd_l1, uint8_t buttons)
00696 {
00697 static xdata uint8_t channel_tab_shadow[GZLL_MAX_CHANNEL_TAB_SIZE] = GZLL_DEFAULT_CHANNEL_TAB;
00698 static xdata uint16_t channel_tab_size = GZLL_DEFAULT_CHANNEL_TAB_SIZE;
00699 static xdata uint16_t channel_page = GZLL_DEFAULT_CHANNEL_TAB_SIZE;
00700
00701 if((buttons & SUB_MENU_INC))
00702 {
00703 channel_page = inc_mod(channel_page, channel_tab_size);
00704 }
00705
00706 if((buttons & SUB_MENU_DEC))
00707 {
00708 channel_page = dec_mod(channel_page, channel_tab_size);
00709 }
00710
00711 if((buttons & VALUE_DEC))
00712 {
00713 if(channel_page == channel_tab_size)
00714 {
00715 channel_tab_size = dec_mod(channel_tab_size, GZLL_MAX_CHANNEL_TAB_SIZE);
00716 channel_page = channel_tab_size;
00717 }
00718 else
00719 {
00720 channel_tab_shadow[channel_page] = (uint8_t)dec_mod(channel_tab_shadow[channel_page], 125);
00721 }
00722
00723 gzll_set_channels(channel_tab_shadow, (uint8_t)channel_tab_size);
00724 }
00725
00726 if((buttons & VALUE_INC) != false)
00727 {
00728 if(channel_page == channel_tab_size)
00729 {
00730 channel_tab_size = inc_mod(channel_tab_size, GZLL_MAX_CHANNEL_TAB_SIZE);
00731 channel_page = channel_tab_size;
00732 }
00733 else
00734 {
00735 channel_tab_shadow[channel_page] = (uint8_t)inc_mod(channel_tab_shadow[channel_page], 125);
00736 }
00737
00738 gzll_set_channels(channel_tab_shadow, (uint8_t)channel_tab_size);
00739 }
00740
00741 if(channel_page == channel_tab_size)
00742 {
00743 strcpy(lcd_l0, "No of channels:");
00744 itoa(channel_tab_size,buffer_a);
00745 strcpy(lcd_l1,buffer_a);
00746 }
00747 else
00748 {
00749 strcpy(buffer_a,"RF channel: ");
00750 itoa(channel_page, buffer_b);
00751 strncat(buffer_a,buffer_b,BUFFER_SIZE - (strlen(buffer_b)-1));
00752 strcpy(lcd_l0, buffer_a);
00753 itoa(channel_tab_shadow[channel_page],buffer_a);
00754 strcpy(lcd_l1, buffer_a);
00755 }
00756 }
00757
00758 void t2_init()
00759 {
00760 T2CON = 0x11;
00761 T2 = CRC = ~((1000 * 4) / 3);
00762 ET2 = 1;
00763 }
00764
00765 T2_ISR()
00766 {
00767 TF2 = 0;
00768
00769 cnt_1ms++;
00770 if(button_db)
00771 {
00772 button_db--;
00773 }
00774 }
00775
00776 TICK_ISR()
00777 {
00778 gzll_timer_tick = true;
00779 gzll_timer_isr_function();
00780 }
00781
00782 uint8_t buttons_read()
00783 {
00784 static xdata uint8_t hold = 0;
00785
00786 uint8_t temp;
00787
00788 if(button_db == 0)
00789 {
00790 temp = BUTTONS;
00791 temp = ~temp;
00792
00793 if(temp)
00794 {
00795 if(hold < BUTTON_HOLD_THRESHOLD)
00796 {
00797 ET2 = 0;
00798 hold++;
00799 button_db = BUTTONS_DEBOUNCE_SLOW;
00800 }
00801 else
00802 {
00803 button_db = BUTTONS_DEBOUNCE_FAST;
00804 }
00805 ET2 = 1;
00806 }
00807 else
00808 {
00809 hold = 0;
00810 }
00811
00812 return temp;
00813 }
00814 else
00815 {
00816 return 0;
00817 }
00818 }
00819
00820 uint16_t inc_mod(uint16_t dat, uint16_t limit)
00821 {
00822 dat++;
00823 if(dat > limit)
00824 {
00825 dat = 0;
00826 }
00827 return dat;
00828 }
00829
00830 uint16_t dec_mod(uint16_t dat, uint16_t limit)
00831 {
00832 if(dat == 0)
00833 {
00834 dat = limit;
00835 }
00836 else
00837 {
00838 dat--;
00839 }
00840 return dat;
00841 }
00842
00843 void itoa(uint16_t i, char * a)
00844 {
00845 uint16_t ord,temp;
00846 uint8_t n;
00847 bool flag = 0;
00848 n = 0;
00849 ord = 10000;
00850
00851 while(ord > 0)
00852 {
00853 temp = i/ord;
00854 if((i/ord) == 0 && !flag)
00855 a[n] = 0x20;
00856 else
00857 {
00858 flag = 1;
00859 a[n] = (uint8_t)(i/ord);
00860 a[n]|= 0x30;
00861 n++;
00862 }
00863 i -= (temp * ord);
00864 ord /= 10;
00865
00866 }
00867 a[n] = '\0';
00868 if(!flag)
00869 {
00870 a[0] = 0|0x30;
00871 a[1] = '\0';
00872 }
00873 }
00874
00875 void strcpy_nrf(char *dest, char const code *src)
00876 {
00877
00878 while(*src != '\0')
00879 {
00880 *dest++ = *src++;
00881 }
00882 *dest = '\0';
00883 }
00884
00885