00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 
00054 
00055 
00056 
00057 
00058 
00059 
00060 
00061 
00062 
00063 
00064 #include <cfg/os.h>
00065 #include <sys/timer.h>
00066 #include <dev/uart.h>
00067 
00068 #include <stdlib.h>
00069 #include <string.h>
00070 #include <io.h>
00071 #include <memdebug.h>
00072 
00073 #include <dev/chat.h>
00074 
00075 uint8_t *chat_report;
00076 
00077 #ifdef NUTDEBUG
00078 
00079 static FILE *__chat_trs;        
00080 static uint8_t __chat_trf;       
00089 void NutTraceChat(FILE * stream, uint8_t flags)
00090 {
00091     if (stream)
00092         __chat_trs = stream;
00093     if (__chat_trs) {
00094         static prog_char dbgfmt[] = "Chat trace flags=0x%02X\n";
00095         __chat_trf = flags;
00096         fprintf_P(__chat_trs, dbgfmt, flags);
00097     } else
00098         __chat_trf = 0;
00099 }
00100 
00101 #endif
00102 
00103 
00104 
00105 
00106 static char *strechr(CONST char *str, int c)
00107 {
00108     while (*str) {
00109         if (*str == '\\') {
00110             if (*++str)
00111                 str++;
00112         } else if (*str == c)
00113             return (char *) str;
00114         else
00115             str++;
00116     }
00117     return 0;
00118 }
00119 
00131 int NutChatExpectString(NUTCHAT * ci, char *str)
00132 {
00133     char ch;
00134     uint8_t m;
00135     uint8_t i;
00136     char *cp = str;
00137 
00138 #ifdef NUTDEBUG
00139     if (__chat_trf) {
00140         static prog_char dbgfmt[] = "Expect '%s', got '";
00141         fprintf_P(__chat_trs, dbgfmt, str);
00142     }
00143 #endif
00144 
00145     while (*cp) {
00146 
00147         
00148 
00149 
00150         if (_read(ci->chat_fd, &ch, 1) != 1) {
00151 #ifdef NUTDEBUG
00152             if (__chat_trf) {
00153                 static prog_char dbgmsg[] = "' TIMEOUT\n";
00154                 fputs_P(dbgmsg, __chat_trs);
00155             }
00156 #endif
00157             return 3;
00158         }
00159 #ifdef NUTDEBUG
00160         if (__chat_trf) {
00161             if (ch > 31 && ch < 127) {
00162                 fputc(ch, __chat_trs);
00163             } else {
00164                 fprintf(__chat_trs, "\\x%02X", ch);
00165             }
00166         }
00167 #endif
00168         
00169 
00170 
00171 
00172         if (ch != *cp) {
00173             cp = str;
00174         }
00175 
00176         
00177 
00178 
00179 
00180         if (ch == *cp) {
00181             cp++;
00182         }
00183 
00184         
00185 
00186 
00187         for (i = 0; i < ci->chat_aborts; i++) {
00188             m = ci->chat_abomat[i];
00189             if (ch == ci->chat_abort[i][m]) {
00190                 if (ci->chat_abort[i][++m] == 0) {
00191 #ifdef NUTDEBUG
00192                     if (__chat_trf) {
00193                         static prog_char dbgmsg[] = "' ABORT\n";
00194                         fputs_P(dbgmsg, __chat_trs);
00195                     }
00196 #endif
00197                     return i + 4;
00198                 }
00199             } else
00200                 m = (ch == ci->chat_abort[i][0]);
00201             ci->chat_abomat[i] = m;
00202         }
00203 
00204         
00205 
00206 
00207         if (ci->chat_report_state > 0) {
00208             m = ci->chat_repmat;
00209             if (ci->chat_report_state == 2) {
00210                 chat_report[m++] = ch;
00211             } else if (ch == ci->chat_report_search[m]) {
00212                 chat_report[m++] = ch;
00213                 if (ci->chat_report_search[m] == 0) {
00214                     ci->chat_report_state = 2;
00215                 }
00216             } else {
00217                 m = (ch == ci->chat_report_search[0]);
00218             }
00219             ci->chat_repmat = m;
00220         }
00221     }
00222 
00223     
00224 
00225 
00226     if (ci->chat_report_state == 2) {
00227         m = ci->chat_repmat;    
00228         while (m < CHAT_MAX_REPORT_SIZE) {
00229             if (_read(ci->chat_fd, &ch, 1) != 1 || ch < ' ') {
00230                 break;
00231             }
00232             chat_report[m++] = ch;
00233 
00234 #ifdef NUTDEBUG
00235             if (__chat_trf) {
00236                 if (ch > 31 && ch < 127) {
00237                     fputc(ch, __chat_trs);
00238                 } else {
00239                     fprintf(__chat_trs, "\\x%02X", ch);
00240                 }
00241             }
00242 #endif
00243         }
00244         ci->chat_report_state = 0;      
00245         chat_report[m] = 0;
00246     }
00247 #ifdef NUTDEBUG
00248     if (__chat_trf) {
00249         static prog_char dbgmsg[] = "'\n";
00250         fputs_P(dbgmsg, __chat_trs);
00251     }
00252 #endif
00253 
00254     return 0;
00255 }
00256 
00257 
00258 
00259 
00260 static int NutChatSendString(int fd, char *str)
00261 {
00262     int rc = 0;
00263     uint8_t eol = 1;
00264     uint8_t skip;
00265     char ch;
00266 
00267 #ifdef NUTDEBUG
00268     if (__chat_trf) {
00269         static prog_char dbgfmt[] = "Send '%s'\n";
00270         fprintf_P(__chat_trs, dbgfmt, str);
00271     }
00272 #endif
00273 
00274     
00275     _read(fd, 0, 0);
00276     while (*str && eol && rc == 0) {
00277         ch = *str++;
00278         skip = 0;
00279         if (ch == '^') {
00280             ch = *str++;
00281             ch &= 0x1f;
00282         } else if (ch == '\\') {
00283             ch = *str++;
00284             switch (ch) {
00285             case 'b':
00286                 ch = '\b';
00287                 break;
00288             case 'c':
00289                 eol = 0;
00290                 skip = 1;
00291                 break;
00292             case 'd':
00293                 NutSleep(1000);
00294                 skip = 1;
00295                 break;
00296             case 'n':
00297                 ch = '\n';
00298                 break;
00299             case 'N':
00300                 ch = 0;
00301                 break;
00302             case 'p':
00303                 NutDelay(100);
00304                 skip = 1;
00305                 break;
00306             case 'r':
00307                 ch = '\r';
00308                 break;
00309             case 's':
00310                 ch = ' ';
00311                 break;
00312             case 't':
00313                 ch = '\t';
00314                 break;
00315             default:
00316                 if (ch >= '0' && ch <= '7') {
00317                     ch &= 0x07;
00318                     if (*str >= '0' && *str <= '7') {
00319                         ch <<= 3;
00320                         ch |= *str++ & 0x07;
00321                         if (*str >= '0' && *str <= '7') {
00322                             ch <<= 3;
00323                             ch |= *str++ & 0x07;
00324                         }
00325                     }
00326                 }
00327                 break;
00328             }
00329         }
00330         if (skip)
00331             skip = 0;
00332         else {
00333             NutDelay(10);
00334             if (_write(fd, &ch, 1) != 1)
00335                 rc = 2;
00336             else
00337                 _write(fd, 0, 0);
00338         }
00339     }
00340     if (eol && rc == 0 && _write(fd, "\r", 1) != 1)
00341         rc = 2;
00342     else
00343         _write(fd, 0, 0);
00344 
00345     return rc;
00346 }
00347 
00348 
00349 
00350 
00351 
00352 
00353 
00354 
00355 
00356 
00357 int NutChatExpect(NUTCHAT * ci, char *str)
00358 {
00359     int rc = 0;
00360     char *reply;
00361     char *subexpect;
00362 
00363     
00364 
00365 
00366     if (strcmp(str, "ABORT") == 0) {
00367         ci->chat_arg = CHAT_ARG_ABORT;
00368         return 0;
00369     }
00370     if (strcmp(str, "TIMEOUT") == 0) {
00371         ci->chat_arg = CHAT_ARG_TIMEOUT;
00372         return 0;
00373     }
00374     if (strcmp(str, "REPORT") == 0) {
00375         ci->chat_repmat = 0;    
00376         ci->chat_report_state = 1;
00377         ci->chat_arg = CHAT_ARG_REPORT;
00378         return 0;
00379     }
00380 
00381     
00382 
00383 
00384     while (str) {
00385         if ((reply = strechr(str, '-')) != 0) {
00386             *reply++ = 0;
00387             if ((subexpect = strechr(reply, '-')) != 0)
00388                 *subexpect++ = 0;
00389         } else
00390             subexpect = 0;
00391 
00392         if ((rc = NutChatExpectString(ci, str)) != 3 || reply == 0)
00393             break;
00394         if ((rc = NutChatSendString(ci->chat_fd, reply)) != 0)
00395             break;
00396         str = subexpect;
00397     }
00398     return rc;
00399 }
00400 
00413 int NutChatSend(NUTCHAT * ci, char *str)
00414 {
00415     char *cp;
00416     char ch;
00417     long lv;
00418 
00419     
00420 
00421 
00422     if (ci->chat_arg == CHAT_ARG_ABORT) {
00423         ci->chat_arg = CHAT_ARG_SEND;
00424 
00425         if (ci->chat_aborts >= CHAT_MAX_ABORTS)
00426             return 1;
00427         cp = malloc(strlen(str) + 1);
00428         ci->chat_abort[ci->chat_aborts++] = cp;
00429         while (*str) {
00430             ch = *str++;
00431             if (ch == '^')
00432                 *cp = *str++ & 0x1f;
00433             else if (ch == '\\') {
00434                 ch = *str++;
00435                 switch (ch) {
00436                 case 'b':
00437                     *cp++ = '\b';
00438                     break;
00439                 case 'n':
00440                     *cp++ = '\n';
00441                     break;
00442                 case 'r':
00443                     *cp++ = '\r';
00444                     break;
00445                 case 's':
00446                     *cp++ = ' ';
00447                     break;
00448                 case 't':
00449                     *cp++ = '\t';
00450                     break;
00451                 default:
00452                     if (ch >= '0' && ch <= '7') {
00453                         ch &= 0x07;
00454                         if (*str >= '0' && *str <= '7') {
00455                             ch <<= 3;
00456                             ch |= *str++ & 0x07;
00457                             if (*str >= '0' && *str <= '7') {
00458                                 ch <<= 3;
00459                                 ch |= *str++ & 0x07;
00460                             }
00461                         }
00462                     }
00463                     if (ch)
00464                         *cp++ = ch;
00465                     break;
00466                 }
00467             } else
00468                 *cp++ = ch;
00469         }
00470         *cp = 0;
00471         return 0;
00472     }
00473 
00474     
00475 
00476 
00477     if (ci->chat_arg == CHAT_ARG_TIMEOUT) {
00478         ci->chat_arg = CHAT_ARG_SEND;
00479 
00480         lv = atol(str) * 1000L;
00481         if (lv <= 0)
00482             lv = CHAT_DEFAULT_TIMEOUT * 1000L;
00483 
00484         _ioctl(ci->chat_fd, UART_SETREADTIMEOUT, &lv);
00485 
00486         return 0;
00487     }
00488 
00489     
00490 
00491 
00492     if (ci->chat_arg == CHAT_ARG_REPORT) {
00493         ci->chat_arg = CHAT_ARG_SEND;
00494         chat_report = malloc(CHAT_MAX_REPORT_SIZE + 1);
00495         cp = malloc(strlen(str) + 1);
00496         ci->chat_report_search = cp;
00497         while (*str)
00498             *cp++ = *str++;     
00499         *cp = 0;
00500 
00501         return 0;
00502     }
00503 
00504     
00505 
00506 
00507     return NutChatSendString(ci->chat_fd, str);
00508 }
00509 
00510 
00516 NUTCHAT *NutChatCreate(int fd)
00517 {
00518     NUTCHAT *ci;
00519 
00520     if ((ci = malloc(sizeof(NUTCHAT))) != 0) {
00521         memset(ci, 0, sizeof(NUTCHAT));
00522         ci->chat_fd = fd;
00523     }
00524     return ci;
00525 }
00526 
00533 void NutChatDestroy(NUTCHAT * ci)
00534 {
00535     uint8_t i;
00536 
00537     if (ci) {
00538         for (i = 0; i < ci->chat_aborts; i++)
00539             free(ci->chat_abort[i]);
00540         free(ci);
00541     }
00542 }
00543 
00552 static int NutChatProc(int fd, char *script)
00553 {
00554     int rc = 0;
00555     char sendflg = 0;
00556     NUTCHAT *ci;
00557     char *arg;
00558     uint32_t to;
00559     uint32_t irto;
00560     uint32_t iwto;
00561 
00562     
00563 
00564 
00565     if ((ci = NutChatCreate(fd)) == 0)
00566         return 2;
00567 
00568     
00569 
00570 
00571     _ioctl(fd, UART_GETREADTIMEOUT, &irto);
00572     _ioctl(fd, UART_GETWRITETIMEOUT, &iwto);
00573     to = 45000;
00574     _ioctl(fd, UART_SETREADTIMEOUT, &to);
00575     to = 5000;
00576     _ioctl(fd, UART_SETWRITETIMEOUT, &to);
00577 
00578     
00579 
00580 
00581 
00582     while (*script && rc == 0) {
00583 
00584         
00585 
00586 
00587         if (*script == ' ' || *script == '\t' || *script == '\r' || *script == '\n') {
00588             script++;
00589             continue;
00590         }
00591 
00592         
00593 
00594 
00595         if (*script == '"' || *script == '\'') {
00596             char quote = *script++;
00597 
00598             arg = script;
00599             while (*script != quote) {
00600                 if (*script == 0) {
00601                     rc = 1;
00602                     break;
00603                 }
00604                 if (*script++ == '\\') {
00605                     if (*script)
00606                         ++script;
00607                 }
00608             }
00609         }
00610 
00611         
00612 
00613 
00614         else {
00615             arg = script;
00616             while (*script && *script != ' ' && *script != '\t' && *script != '\r' && *script != '\n')
00617                 ++script;
00618         }
00619 
00620         if (*script)
00621             *script++ = 0;
00622 
00623         
00624 
00625 
00626         if (rc == 0) {
00627             if (sendflg)
00628                 rc = NutChatSend(ci, arg);
00629             else
00630                 rc = NutChatExpect(ci, arg);
00631             sendflg = !sendflg;
00632         }
00633     }
00634 
00635     
00636 
00637 
00638     _ioctl(fd, UART_SETREADTIMEOUT, &irto);
00639     _ioctl(fd, UART_SETWRITETIMEOUT, &iwto);
00640 
00641     
00642 
00643 
00644     NutChatDestroy(ci);
00645 
00646     return rc;
00647 }
00648 
00662 int NutChat(int fd, CONST char *script)
00663 {
00664     int rc = -1;
00665     char *buf;
00666 
00667     
00668 
00669 
00670     if ((buf = strdup(script)) != NULL) {
00671         rc = NutChatProc(fd, buf);
00672         free(buf);
00673     }
00674     return rc;
00675 }
00676 
00688 #ifdef __HARVARD_ARCH__
00689 int NutChat_P(int fd, PGM_P script)
00690 {
00691     int rc = -1;
00692     char *buf;
00693 
00694     
00695 
00696 
00697     if ((buf = malloc(strlen_P(script) + 1)) != 0) {
00698         strcpy_P(buf, script);
00699         rc = NutChatProc(fd, buf);
00700         free(buf);
00701     }
00702     return rc;
00703 }
00704 #endif