NM500 / Mbed 2 deprecated NeuroShield_Gesture_Recognition

Dependencies:   mbed NeuroShield_SDFileSystem NeuroShield

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /******************************************************************************
00002  *  NM500 NeuroShield Board (Alphabet) Gesture Recognition Demo
00003  *  revision 1.1.5, 2020/02/11
00004  *  Copyright (c) 2017 nepes inc.
00005  *
00006  *  Please use the NeuroShield library v1.1.5 or later
00007  ******************************************************************************/
00008  
00009 #include "mbed.h"
00010 #include <NeuroShield.h>
00011 #include <NeuroShieldSPI.h>
00012 #include <mpu6050.h>
00013 #include "SDFileSystem.h"
00014 
00015 //#define CALCULATE_TIME
00016 
00017 #define DEFAULT_MAXIF   0x2000
00018 
00019 #define UPPER_LIMIT         600
00020 #define LOWER_LIMIT         100
00021 #define IGNORE_CAPTURE_LEN  70
00022 #define CAPTURE_LENGTH      256     //384
00023 #define CAPTURE_LEN_FLOAT   256.0   //384.0
00024 
00025 NeuroShield hnn;
00026 MPU6050 mpu(0x68, PB_9, PB_8);
00027 SDFileSystem sd(D11, D12, D13, D10, "sd");
00028 Serial pc(USBTX, USBRX);
00029 
00030 DigitalOut sdcard_ss(D6);
00031 DigitalOut arduino_con(D5);
00032 //DigitalOut trig_port(D10);
00033 
00034 bool sd_detected = false;
00035 
00036 int16_t ax, ay, az, gx, gy, gz;
00037 
00038 uint8_t learn_cat = 0;           // category to learn
00039 uint8_t precat = 0;              // previously recognized category
00040 uint16_t learn_len;
00041 uint16_t read_cat[6], read_dist[6], read_nid[6];
00042 uint16_t nsr, ncount;            // response from the neurons
00043 uint16_t prev_ncount = 0;
00044 uint16_t fpga_version;
00045 
00046 #if defined(CALCULATE_TIME)
00047 Timer timer;
00048 unsigned long cal_time[3];
00049 #endif
00050 
00051 uint8_t vector_ax[NEURON_SIZE];
00052 uint8_t vector_ay[NEURON_SIZE];
00053 uint8_t vector_az[NEURON_SIZE];
00054 uint8_t vector_gx[NEURON_SIZE];
00055 uint8_t vector_gy[NEURON_SIZE];
00056 uint8_t vector_gz[NEURON_SIZE];
00057 
00058 int16_t capture_ax[CAPTURE_LENGTH];
00059 int16_t capture_ay[CAPTURE_LENGTH];
00060 int16_t capture_az[CAPTURE_LENGTH];
00061 int16_t capture_gx[CAPTURE_LENGTH];
00062 int16_t capture_gy[CAPTURE_LENGTH];
00063 int16_t capture_gz[CAPTURE_LENGTH];
00064 
00065 uint16_t neuron_data[260];
00066 
00067 int16_t extractFeatureVector(int wait_value)
00068 {
00069     int i;
00070     uint8_t capture_start = 0;
00071     uint16_t capture_count = 0, wait_count = 0;;
00072     int16_t check_g = -1;       // 1:capture, 0:capture-end, -1:wait-input
00073     int16_t max_a = -1, min_a = 0x4000, max_g = -1, min_g = 0x4000;
00074     
00075 #if defined(CALCULATE_TIME)
00076     timer.start();
00077     cal_time[0] = timer.read_ms();
00078 #endif
00079 
00080     for (i = 0; i < NEURON_SIZE; i++) {
00081         vector_ax[i] = 0;
00082         vector_ay[i] = 0;
00083         vector_az[i] = 0;
00084         vector_gx[i] = 0;
00085         vector_gy[i] = 0;
00086         vector_gz[i] = 0;
00087     }
00088     for (i = 0; i < CAPTURE_LENGTH; i++) {
00089         capture_ax[i] = 0;
00090         capture_ay[i] = 0;
00091         capture_az[i] = 0;
00092         capture_gx[i] = 0;
00093         capture_gy[i] = 0;
00094         capture_gz[i] = 0;
00095     }
00096     
00097     while (1) {
00098         for (i = 0; i < 6; i++) {
00099             mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
00100         }
00101             
00102         if ((gx > UPPER_LIMIT) || (gx < (0 - UPPER_LIMIT)) || (gy > UPPER_LIMIT) || (gy < (0 - UPPER_LIMIT)) || (gz > UPPER_LIMIT) || (gz < (0 - UPPER_LIMIT)))
00103             check_g = 1;
00104         else if ((gx < LOWER_LIMIT) && (gx > (0 - LOWER_LIMIT)) && (gy < LOWER_LIMIT) && (gy > (0 - LOWER_LIMIT)) && (gz < LOWER_LIMIT) && (gz > (0 - LOWER_LIMIT)))
00105             check_g = 0;
00106         else
00107             check_g = -1;
00108             
00109         if (capture_start == 0) {
00110             if (check_g == 1) {
00111                 capture_start = 1;
00112             }
00113             else {
00114                 wait_count++;
00115                 if (wait_count >= wait_value) {
00116                     return(-1);    // timeout
00117                 }
00118             }
00119         }
00120         else if (capture_start == 1) {
00121             if (check_g == 0) {
00122                 capture_start = 0;
00123                 break;             // go to feature extraction
00124             }
00125             else {
00126                 if (ax > max_a) max_a = ax; else if (ax < min_a) min_a = ax;
00127                 if (ay > max_a) max_a = ay; else if (ay < min_a) min_a = ay;
00128                 if (az > max_a) max_a = az; else if (az < min_a) min_a = az;
00129                 if (gx > max_g) max_g = gx; else if (gx < min_g) min_g = gx;
00130                 if (gy > max_g) max_g = gy; else if (gy < min_g) min_g = gy;
00131                 if (gz > max_g) max_g = gz; else if (gz < min_g) min_g = gz;
00132                 
00133                 capture_ax[capture_count] = ax;
00134                 capture_ay[capture_count] = ay;
00135                 capture_az[capture_count] = az;
00136                 capture_gx[capture_count] = gx;
00137                 capture_gy[capture_count] = gy;
00138                 capture_gz[capture_count] = gz;
00139                 
00140                 capture_count++;
00141                 if (capture_count >= CAPTURE_LENGTH) {
00142                     printf("capture_count = %d\n", capture_count);
00143                     return(0);  // exceed data length
00144                 }
00145             }
00146         }
00147     }
00148 
00149 #if defined(CALCULATE_TIME)
00150     cal_time[1] = timer.read_ms();
00151 #endif
00152     
00153     for (i = 0; i < NEURON_SIZE; i++) {
00154         uint16_t base_index;
00155         float base_ratio, next_ratio, resample_ax, resample_ay, resample_az, resample_gx, resample_gy, resample_gz;
00156         
00157         next_ratio = (float)i;
00158         next_ratio = next_ratio * capture_count / CAPTURE_LEN_FLOAT;
00159         base_index = (uint16_t)next_ratio;
00160         next_ratio = next_ratio - base_index;
00161         base_ratio = 1.0 - next_ratio;
00162         
00163         resample_ax = (base_ratio * capture_ax[base_index]) + (next_ratio * capture_ax[base_index + 1]);
00164         resample_ay = (base_ratio * capture_ay[base_index]) + (next_ratio * capture_ay[base_index + 1]);
00165         resample_az = (base_ratio * capture_az[base_index]) + (next_ratio * capture_az[base_index + 1]);
00166         resample_gx = (base_ratio * capture_gx[base_index]) + (next_ratio * capture_gx[base_index + 1]);
00167         resample_gy = (base_ratio * capture_gy[base_index]) + (next_ratio * capture_gy[base_index + 1]);
00168         resample_gz = (base_ratio * capture_gz[base_index]) + (next_ratio * capture_gz[base_index + 1]);
00169         
00170         resample_ax = (resample_ax - min_a) * 255 / (max_a - min_a);
00171         resample_ay = (resample_ay - min_a) * 255 / (max_a - min_a);
00172         resample_az = (resample_az - min_a) * 255 / (max_a - min_a);
00173         resample_gx = (resample_gx - min_g) * 255 / (max_g - min_g);
00174         resample_gy = (resample_gy - min_g) * 255 / (max_g - min_g);
00175         resample_gz = (resample_gz - min_g) * 255 / (max_g - min_g);
00176         
00177         vector_ax[i] = (uint8_t)resample_ax;
00178         vector_ay[i] = (uint8_t)resample_ay;
00179         vector_az[i] = (uint8_t)resample_az;
00180         vector_gx[i] = (uint8_t)resample_gx;
00181         vector_gy[i] = (uint8_t)resample_gy;
00182         vector_gz[i] = (uint8_t)resample_gz;
00183     }
00184 
00185 #if defined(CALCULATE_TIME)
00186     cal_time[2] = timer.read_ms();
00187     printf("Total: %dms, [1]: %dms, [2]: %dms\n", (unsigned long)(cal_time[2] - cal_time[0]), (unsigned long)(cal_time[1] - cal_time[0]), (unsigned long)(cal_time[2] - cal_time[1]));
00188 #endif
00189     
00190     return(capture_count);
00191 }
00192 
00193 void neuron2Sd()
00194 {
00195     uint16_t nm_nsr, nm_cnt;
00196     
00197     sdcard_ss = LOW;
00198     FILE* fp = fopen("/sd/backup.hex", "wb+");
00199     sdcard_ss = HIGH;
00200     if (fp == NULL) {
00201         printf("Error opening backup.hex\n");
00202     }
00203     else {
00204         printf("Save neuron data to SD-CARD (backup.hex) ");
00205         nm_nsr = hnn.getNsr();
00206         nm_cnt = hnn.getNcount();
00207         if ((nm_cnt == 0xFFFF) || (nm_cnt == 0x7FFF)) {
00208             sdcard_ss = LOW;
00209             fclose(fp);
00210             sdcard_ss = HIGH;
00211             printf("  neuron full!!\n");
00212             return;
00213         }
00214         
00215         uint16_t header[4] = { 0x1704, 0, 0, 0 };
00216         header[1] = NEURON_SIZE;
00217         header[2] = ncount = hnn.getNcount();
00218         //header[3] = reserved for upper byte of ncount
00219         
00220         sdcard_ss = LOW;
00221         fwrite(header, (sizeof(uint16_t)), 4, fp);
00222         sdcard_ss = HIGH;
00223         
00224         for (int i = 0; i < NEURON_SIZE; i++)
00225             capture_ax[i] = 0;
00226         
00227         hnn.setNsr(0x0010);
00228         hnn.resetChain();
00229         for (int i = 1; i <= nm_cnt; i++) {
00230             // read neuron data from NM500
00231             neuron_data[0] = hnn.getNcr();
00232             hnn.readCompVector(&neuron_data[1], NEURON_SIZE);
00233             neuron_data[257] = hnn.getAif();
00234             neuron_data[258] = hnn.getMinif();
00235             neuron_data[259] = hnn.getCat();
00236             
00237             // save data to backup.hex
00238             sdcard_ss = LOW;
00239             fwrite(neuron_data, sizeof(uint16_t), 260, fp);
00240             sdcard_ss = HIGH;
00241             
00242             if (!(i % 10))
00243                 printf(".");
00244         }
00245         hnn.setNsr(nm_nsr);
00246         
00247         sdcard_ss = LOW;
00248         fclose(fp);
00249         sdcard_ss = HIGH;
00250         
00251         printf(". Done(%d)\n", nm_cnt);
00252     }
00253 }
00254 
00255 void sd2Neuron()
00256 {
00257     uint16_t nm_nsr;
00258     
00259     sdcard_ss = LOW;
00260     FILE* fp = fopen("/sd/backup.hex", "r");
00261     sdcard_ss = HIGH;
00262     if (fp == NULL) {
00263         printf("  Error opening backup.hex\n");
00264     }
00265     else {
00266         printf("Restore neuron data from SD-CARD (backup.hex) ");
00267         
00268         uint16_t header[4];
00269         sdcard_ss = LOW;
00270         fread(header, (sizeof(uint16_t)), 4, fp);
00271         sdcard_ss = HIGH;
00272         if (header[0] != 0x1704) {
00273             printf("Header error\n");
00274             return;
00275         }
00276         if (header[1] != NEURON_SIZE) {
00277             printf("Neuron size error\n");
00278             return;
00279         }
00280         if (header[2] > hnn.total_neurons) {
00281             printf("Ncount error\n");
00282             return;
00283         }
00284         ncount = header[2];    
00285         
00286         nm_nsr = hnn.getNsr();
00287         hnn.forget();
00288         hnn.setNsr(0x0010);
00289         hnn.resetChain();
00290         
00291         // read from SD
00292         for (int i = 1; i <= ncount; i++) {
00293             sdcard_ss = LOW;
00294             fread(neuron_data, (sizeof(uint16_t)), 260, fp);
00295             sdcard_ss = HIGH;
00296 
00297             hnn.setNcr(neuron_data[0]);
00298             hnn.writeCompVector(&neuron_data[1], NEURON_SIZE);
00299             hnn.setAif(neuron_data[257]);
00300             hnn.setMinif(neuron_data[258]);
00301             hnn.setCat(neuron_data[259]);
00302             
00303             if (!(i % 10))
00304                 printf(".");
00305         }        
00306         hnn.setNsr(nm_nsr);
00307         hnn.setMaxif(DEFAULT_MAXIF);
00308 
00309         sdcard_ss = LOW;
00310         fclose(fp);
00311         sdcard_ss = HIGH;
00312         
00313         printf(". Done(%d)\n", ncount);
00314     }
00315 }
00316 
00317 void displayNeurons()
00318 {
00319     uint16_t nm_ncr, nm_aif, nm_cat, nm_cnt;
00320     
00321     // display the content of the committed neurons
00322     nm_cnt = hnn.getNcount();
00323     printf("  Display the neurons, ncount=%d\n", nm_cnt);
00324     uint16_t temp_nsr = hnn.getNsr();
00325     hnn.setNsr(0x0010);
00326     hnn.resetChain();
00327     for (int i = 1; i <= nm_cnt; i++) {
00328         nm_ncr = hnn.getNcr();
00329         hnn.readCompVector(neuron_data, NEURON_SIZE);
00330         nm_aif = hnn.getAif();
00331         nm_cat = hnn.getCat();
00332         printf("  neuron#%d \tvector=", i);
00333         for (int j = 0; j < 30;/*NEURON_SIZE;*/ j++) {
00334             printf("0x%02x, ", neuron_data[j]);
00335         }
00336         printf(" \tncr=%d, \taif=%d, \tnm_cat=%d", nm_ncr, nm_aif, (nm_cat & 0x7FFF));
00337         if (nm_cat & 0x8000) printf(" (degenerated)");
00338         printf("\n");
00339     }
00340     hnn.setNsr(temp_nsr);
00341 }
00342 
00343 void mpu6050Calibration()
00344 {
00345     int i, j;
00346     int32_t sum_ax = 0, sum_ay = 0, sum_az = 0, sum_gx = 0, sum_gy = 0, sum_gz = 0;
00347     int16_t mean_ax, mean_ay, mean_az, mean_gx, mean_gy, mean_gz;
00348     int16_t ax_offset, ay_offset, az_offset, gx_offset, gy_offset, gz_offset;
00349     
00350     for (i = 0; i < 100; i++) {
00351         mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
00352     }
00353     
00354     for (j = 0; j < 5; j++) {
00355         for (i = 0; i < 100; i++) {
00356             mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
00357             sum_ax += ax;
00358             sum_ay += ay;
00359             sum_az += az;
00360             sum_gx += gx;
00361             sum_gy += gy;
00362             sum_gz += gz;
00363         }
00364         
00365         mean_ax = sum_ax / 100;
00366         mean_ay = sum_ay / 100;
00367         mean_az = sum_az / 100;
00368         mean_gx = sum_gx / 100;
00369         mean_gy = sum_gy / 100;
00370         mean_gz = sum_gz / 100;
00371         
00372         // MPU6050_GYRO_FS_1000 : offset = (-1) * mean_g
00373         // MPU6050_ACCEL_FS_8   : offset = (-0.5) * mean_a
00374         ax_offset = (-mean_ax) / 2;
00375         ay_offset = (-mean_ay) / 2;
00376         az_offset = (-mean_az) / 2;
00377         gx_offset = -mean_gx;
00378         gy_offset = -mean_gy;
00379         gz_offset = -mean_gz;
00380         
00381         // set
00382         mpu.setXAccelOffset(ax_offset);
00383         mpu.setYAccelOffset(ay_offset);
00384         mpu.setZAccelOffset(az_offset);
00385         mpu.setXGyroOffset(gx_offset);
00386         mpu.setYGyroOffset(gy_offset);
00387         mpu.setZGyroOffset(gz_offset);
00388     }
00389 }
00390 
00391 int main()
00392 {
00393     int i, input_key[2];
00394     uint8_t firing_cat_cnt[27];
00395     
00396     arduino_con = LOW;
00397     sdcard_ss = HIGH;
00398     wait(0.5);
00399     
00400     if (hnn.begin() != 0) {
00401         fpga_version = hnn.fpgaVersion();
00402         if ((fpga_version & 0xFF00) == 0x0000) {
00403             printf("\n\n#### NeuroShield Board (Board v%d.0 / FPGA v%d.0) ####\n", ((fpga_version >> 4) & 0x000F), (fpga_version & 0x000F));
00404         }
00405         else if ((fpga_version & 0xFF00) == 0x0100) {
00406             printf("\n\n#### Prodigy Board (Board v%d.0 / FPGA v%d.0) ####\n", ((fpga_version >> 4) & 0x000F), (fpga_version & 0x000F));
00407         }
00408         else {
00409             printf("\n\n#### Unknown Board (Board v%d.0 / FPGA v%d.0) ####\n", ((fpga_version >> 4) & 0x000F), (fpga_version & 0x000F));
00410         }
00411         printf("\nStart NM500 initialization...\n");
00412         printf("  NM500 is initialized!\n");
00413         printf("  There are %d neurons\n", hnn.total_neurons);
00414         hnn.setMaxif(DEFAULT_MAXIF);
00415     }
00416     else {
00417         printf("\n\nStart NM500 initialization...\n");
00418         printf("  NM500 is not connected properly!!\n");
00419         printf("  Please check the connection and reboot!\n");
00420         while (1);
00421     }
00422     
00423     // initialize SD card
00424     printf("\nStart SD-CARD initialization...\n");
00425     sdcard_ss = LOW;
00426     mkdir("/sd/testdir", 0777);
00427     FILE *fp = fopen("/sd/testdir/sdtest.txt", "w");
00428     if (fp == NULL) {
00429         printf("  SD-CARD initialization failed\n");
00430         printf("  Insert SD-CARD and reboot\n");
00431         fclose(fp);
00432         while (1);
00433     }
00434     else {
00435         printf("  SD-CARD initialization success\n");
00436         sd_detected = true;
00437         fprintf(fp, "Hello World!");
00438         fclose(fp);
00439     }
00440     sdcard_ss = HIGH;
00441     
00442     // initialize mpu6050
00443     printf("\nStart MPU-6050 initialization...\n");
00444     mpu.initialize();
00445     // set gyro & accel range
00446     mpu.setFullScaleGyroRange(MPU6050_GYRO_FS_1000);
00447     mpu.setFullScaleAccelRange(MPU6050_ACCEL_FS_8);
00448     
00449     // verify connection
00450     for (i = 0; i < 10; i++) {
00451         if (mpu.testConnection()) {
00452             printf("  MPU-6050 is connected successfully\n");
00453             break;
00454         }
00455         else if (i == 9) {
00456             printf("  MPU-6050 connection failed\n");
00457             printf("  Please check the connection and reboot!\n");
00458             while (1);
00459         }
00460         wait(0.1);
00461     }
00462     
00463     // wait for ready
00464     printf("  Trying to calibrate. Make sure the board is stable and upright\n");
00465     // reset offsets
00466     mpu.setXAccelOffset(0);
00467     mpu.setYAccelOffset(0);
00468     mpu.setZAccelOffset(0);
00469     mpu.setXGyroOffset(0);
00470     mpu.setYGyroOffset(0);
00471     mpu.setZGyroOffset(0);
00472     mpu6050Calibration();
00473     printf("  MPU-6050 calibration is complete!!\n\n");
00474     
00475     //sd2Neuron();
00476     
00477     printf("Alphabet Gesture Recognition loop...\n");
00478     printf("Type Alphabet and enter, to learn alphabet motion\n");
00479     printf("Type '1' and enter, to save Neuron to SD-CARD\n");
00480     printf("Type '2' and enter, to restore Neuron from SD-CARD\n\n");
00481     
00482     // main loop
00483     while (1) {
00484         if (pc.readable()) {
00485             input_key[0] = input_key[1];
00486             input_key[1] = pc.getc();
00487             
00488             if (input_key[1] == 0x0D) {     // enter key
00489                 learn_cat = input_key[0];
00490                 if (learn_cat == '1') {
00491                     //displayNeurons();
00492                     neuron2Sd();
00493                 }
00494                 else if (learn_cat == '2') {
00495                     sd2Neuron();
00496                     //displayNeurons();
00497                 }
00498                 else if (learn_cat == '5') {
00499                     displayNeurons();
00500                 }
00501                 else if (learn_cat == '9') {
00502                     printf("\nClear neuron data\n");
00503                     hnn.forget();
00504                     hnn.setMaxif(DEFAULT_MAXIF);
00505                     ncount = hnn.getNcount();
00506                 }
00507                 else if ((learn_cat == '0') || ((learn_cat >= 'a') && (learn_cat <= 'z')) || ((learn_cat >= 'A') && (learn_cat <= 'Z'))) {
00508                     if (learn_cat == '0')
00509                         learn_cat = 0;
00510                     else if (learn_cat <= 'Z')
00511                         learn_cat = learn_cat - 'A' + 1;
00512                     else
00513                         learn_cat = learn_cat - 'a' + 1;
00514                     printf("Learning motion category '%c'\n", (learn_cat + 'A' - 1));
00515                     
00516                     learn_len = extractFeatureVector(300);
00517                     
00518                     if (learn_len > IGNORE_CAPTURE_LEN) {
00519                         hnn.setContext(1);     // ax
00520                         hnn.learn(vector_ax, NEURON_SIZE, learn_cat);
00521                         hnn.setContext(2);     // ay
00522                         hnn.learn(vector_ay, NEURON_SIZE, learn_cat);
00523                         hnn.setContext(3);     // az
00524                         hnn.learn(vector_az, NEURON_SIZE, learn_cat);
00525                         hnn.setContext(4);     // gx
00526                         hnn.learn(vector_gx, NEURON_SIZE, learn_cat);
00527                         hnn.setContext(5);     // gy
00528                         hnn.learn(vector_gy, NEURON_SIZE, learn_cat);
00529                         hnn.setContext(6);     // gz
00530                         ncount = hnn.learn(vector_gz, NEURON_SIZE, learn_cat);
00531                         
00532                         printf("  Neurons=%d, learn_len=%d\n\n", ncount, learn_len);
00533                     }
00534                     else {
00535                         printf("  Learning Error: timeout or exceed data length\n\n");
00536                     }
00537                 }
00538             }
00539         }
00540         else {
00541             // recognize
00542             learn_len = extractFeatureVector(4);
00543             if (learn_len > IGNORE_CAPTURE_LEN) {
00544                 hnn.setContext(1);     // ax
00545                 hnn.classify(vector_ax, NEURON_SIZE, &read_dist[0], &read_cat[0], &read_nid[0]);
00546                 hnn.setContext(2);     // ay
00547                 hnn.classify(vector_ay, NEURON_SIZE, &read_dist[1], &read_cat[1], &read_nid[1]);
00548                 hnn.setContext(3);     // az
00549                 hnn.classify(vector_az, NEURON_SIZE, &read_dist[2], &read_cat[2], &read_nid[2]);
00550                 hnn.setContext(4);     // gx
00551                 hnn.classify(vector_gx, NEURON_SIZE, &read_dist[3], &read_cat[3], &read_nid[3]);
00552                 hnn.setContext(5);     // gy
00553                 hnn.classify(vector_gy, NEURON_SIZE, &read_dist[4], &read_cat[4], &read_nid[4]);
00554                 hnn.setContext(6);     // gz
00555                 hnn.classify(vector_gz, NEURON_SIZE, &read_dist[5], &read_cat[5], &read_nid[5]);
00556                 
00557                 for (i = 0; i < 27; i++) {
00558                     firing_cat_cnt[i] = 0;
00559                 }
00560                 
00561                 for (i = 0; i < 6; i++) {
00562                     if ((read_cat[i] >= 1) && (read_cat[i] <= 26)) {
00563                         firing_cat_cnt[read_cat[i]]++;
00564                     }
00565                 }
00566                 
00567                 for (i = 0; i < 6; i++)
00568                     read_dist[i] = read_dist[i] & 0x7FFF;
00569                 
00570                 for (i = 1; i < 27; i++) {
00571                     if (firing_cat_cnt[i] >= 3) {
00572                         int firing_cat = i + 'A' - 1;
00573                         printf("%c\n", firing_cat);
00574                     }
00575                 }
00576                 
00577 #if 0 // for debug
00578                 printf("%d", learn_len);
00579                 for (i = 0; i < 6; i++) {
00580                     if ((read_cat[i] >= 1) && (read_cat[i] <= 26))
00581                         printf(" \t[%c(%d),%d,%d]", (read_cat[i] + 'A' - 1), read_cat[i], read_dist[i], read_nid[i]);
00582                     else
00583                         printf(" \t[0x%04X,%d,%d]", read_cat[i], read_dist[i], read_nid[i]);
00584                 }
00585                 printf("\n");
00586 #endif
00587             }
00588 #if 0 // for debug
00589             else {
00590                 printf(", %d", learn_len);
00591             }
00592 #endif
00593         }
00594     }
00595 }