home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / prog / utils / sercli.shr / sercli / src / sercli.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-16  |  13.4 KB  |  743 lines

  1. /*
  2. **  $Source: WB_2.1:homes/rkr/prog/sercli/src/RCS/sercli.c,v $
  3. **  $Author: rkr $
  4. **  $Revision: 1.13 $
  5. **  $Locker: rkr $
  6. **  $State: Exp $
  7. **  $Date: 1993/06/16 23:27:34 $
  8. **
  9. **  sercli (an Amiga .device <-> FIFO interface tool)
  10. **  Copyright (C) 1993  Richard Rauch
  11. **
  12. **  See /doc/sercli.doc and /COPYING for use and distribution license.
  13. **
  14. */
  15.  
  16. #include <exec/types.h>
  17. #include <exec/io.h>
  18. #include <exec/lists.h>
  19. #include <exec/memory.h>
  20. #include <exec/nodes.h>
  21. #include <exec/ports.h>
  22. #include <devices/serial.h>
  23. #include <devices/timer.h>
  24. #include <intuition/intuition.h>
  25. #include <intuition/intuitionbase.h>
  26. #include <libraries/dos.h>
  27.  
  28. #ifdef AZTEC_C
  29. #include <functions.h>
  30. #else
  31. #include <clib/alib_protos.h>
  32. #include <clib/dos_protos.h>
  33. #include <clib/exec_protos.h>
  34. #include <clib/intuition_protos.h>
  35. #endif
  36.  
  37. #include "defs.h"
  38. #include "ser_supp.h"
  39. #include "misc.h"
  40. #include "fifo.h"
  41. #include "config.h"
  42. #include "sercli-config.h"
  43. #include "rexx.h"
  44. #include "version.h"
  45.  
  46.  
  47. #define COPYRIGHT_NOTICE            \
  48. "\n"                                            \
  49. "$VER: " NAME " " VERSION " (" __DATE__")\n"    \
  50. "Copyright (C) 1991, 1993 by Richard Rauch.\n"  \
  51. "No warranty; distribute at will.\n"            \
  52. "(see doc/sercli.doc for more info)\n"          \
  53. "(see also the GNU General Public License)\n"   \
  54. "\n"
  55.  
  56.  
  57. #define SER_READ_MAX  512
  58. #define FIFO_BUF_SIZE (SER_READ_MAX * 4)
  59.  
  60. #define CTRL(x) (x ^ '@')
  61.  
  62. #define dput(x) write_ser_str (x)   /*** for debugging only ***/
  63.  
  64. /*
  65. **  FIFO related globals.
  66. **
  67. */
  68. char *FifoSlav;      /* fifo_s    */
  69. char *FifoMast;      /* fifo_m    */
  70. char FifrIP;         /* read msg pending    */
  71. char FifwIP;         /* write msg pending   */
  72. long *FifoBase;
  73. Message RMsg;
  74. Message WMsg;
  75. MsgPort *FifoSink;
  76. void *FifoR;
  77. void *FifoW;
  78. ULONG pmask;
  79.  
  80. char *nether_name;        /***  who/what is on the other end...    ***/
  81.  
  82. int alert_ser = 0;
  83. int alert_loc = 1;
  84. char *config_file_name;
  85.  
  86.  
  87. /*
  88. **  Intuition/Window related globals
  89. **
  90. */
  91. NewWindow nw =
  92. {
  93.     0, 0, 0, 0,
  94.     0, 1,
  95.  
  96.     CLOSEWINDOW,    /*** IDCMP ***/
  97.  
  98.     NOCAREREFRESH | SMART_REFRESH | WINDOWCLOSE | WINDOWDEPTH
  99.     | WINDOWDRAG,   /*** Flags ***/
  100.  
  101.     NULL, NULL,
  102.     NULL,        /*** title ***/
  103.     NULL,
  104.     NULL,
  105.     0, 0, 0, 0,
  106.     WBENCHSCREEN
  107. };
  108. Window *win;
  109. char *window_title;  /*** Just use nw.Title??? ***/
  110. WORD win_width;
  111. WORD win_height;
  112. ULONG imask;
  113.  
  114.  
  115. ULONG wake_flags;   /*** Mask of bits to Wait() on. ***/
  116.  
  117.  
  118. static void clean_up (void);
  119. static void init (void);
  120.  
  121.  
  122. /*
  123. **  DICE (and maybe Lattice/SAS, dunno) uses a function, onbreak() to allow
  124. **  you to control what happens when a ^c occurs.
  125. **
  126. **  Aztec allows ^c checking to be turned off with a global flag variable.
  127. **
  128. **    ---rkr.
  129. **
  130. */
  131. #ifdef AZTEC_C
  132. extern long Enable_Abort;
  133. void onbreak (int (*brk) (void) ) {}
  134. #else
  135. long Enable_Abort;
  136. #endif
  137.  
  138.  
  139. void hex_dump (char *buf, size_t len)
  140. {
  141.     while (len--)
  142.     {
  143.     char c = *buf;
  144.     static char hex_chars [] =
  145.     {
  146.         '0', '1', '2', '3', '4', '5', '6', '7',
  147.         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
  148.     };
  149.  
  150.     putchar (hex_chars [(c >> 4) & 0xf]);
  151.     putchar (hex_chars [ c       & 0xf]);
  152.  
  153.     if (len)
  154.     {
  155.         putchar (' ');
  156.         putchar (' ');
  157.     }
  158.  
  159.     ++buf;
  160.     }
  161. }
  162.  
  163.  
  164.  
  165. void on_error_ser (void *ptr)
  166. {
  167.     char *cmd;
  168.     char *err;
  169.     char err_buf [50];
  170.     IOExtSer *ior;
  171.     static char *serial_errors [] =
  172.     {
  173.     "not an error...",
  174.     "Device in use",
  175.     "unused",
  176.     "Invalid bps rate",
  177.     "Out of memory",
  178.     "Bad parameter",
  179.     "hardware data overrun (hmmm)",
  180.     "unused",
  181.     "unused",
  182.     "`ParityErr'",
  183.     "unused",
  184.     "`TimeErr'",
  185.     "BufOverflow'",
  186.     "No DSR",
  187.     "No CTS",
  188.     "`DetectedBreak'",
  189.     };
  190.  
  191.  
  192.     ior = ptr;
  193.  
  194.     printf
  195.     (
  196.     "\n***\nserial error on {%s}; %s/%d\n",
  197.     prog_id,
  198.     ser_device_name,
  199.     ser_device_unit
  200.     );
  201.  
  202.     switch (ior->IOSer.io_Command)
  203.     {
  204.     case CMD_WRITE:
  205.     cmd = "CMD_WRITE";
  206.     break;
  207.  
  208.     case CMD_READ:
  209.     cmd = "CMD_READ";
  210.     break;
  211.  
  212.     case SDCMD_QUERY:
  213.     cmd = "SDCMD_QUERY";
  214.     break;
  215.  
  216.     case SDCMD_SETPARAMS:
  217.     cmd = "SDCMD_SETPARAMS";
  218.     break;
  219.  
  220.     default:
  221.     cmd = "duh?";
  222.     break;
  223.     }
  224.  
  225.     if ( (ior->IOSer.io_Error > 0) && (ior->IOSer.io_Error < 16) )
  226.     err = serial_errors [ior->IOSer.io_Error];
  227.     else
  228.     {
  229.     err = err_buf;
  230.     sprintf (err_buf, "Unknown error number, %d", ior->IOSer.io_Error);
  231.     }
  232.  
  233.     printf
  234.     (
  235.     "{\n"
  236.     "\tio_Command       == %s\n"
  237.     "\tio_Flags         == 0x%08.8x\n"
  238.     "\tio_Error         == %d: %s\n"
  239.     "\tio_Actual        == %d\n"
  240.     "\tio_Length        == %d\n"
  241.     "\tio_Data          == 0x%x\n"
  242.     "\tio_ExtFlags      == 0x%08.8x\n"
  243.     "\tio_Baud          == %d\n"
  244.     "\tio_ReadLen       == %d\n"
  245.     "\tio_WriteLen      == %d\n"
  246.     "\tio_StopBits      == %d\n"
  247.     "\tio_SerFlags      == 0x%08.8x\n"
  248.     "\tio_Status        == %d\n"
  249.     "}\n",
  250.     cmd,
  251.     ior->IOSer.io_Flags,
  252.     ior->IOSer.io_Error, err,
  253.     ior->IOSer.io_Actual,
  254.     ior->IOSer.io_Length,
  255.     ior->IOSer.io_Data,
  256.     ior->io_ExtFlags,
  257.     ior->io_Baud,
  258.     ior->io_ReadLen,
  259.     ior->io_WriteLen,
  260.     ior->io_StopBits,
  261.     ior->io_SerFlags,
  262.     ior->io_Status
  263.     );
  264.  
  265.     printf ("io_Data contents == {");
  266.     hex_dump (ior->IOSer.io_Data, ior->IOSer.io_Length);
  267.     printf ("}\n\n");
  268. }
  269.  
  270.  
  271. void open_fifo (void)
  272. {
  273.     FifoSlav = malloc (strlen (prog_id) + 16);
  274.     FifoMast = malloc (strlen (prog_id) + 16);
  275.     if (!(FifoSlav && FifoMast) )
  276.     {
  277.     fprintf (stderr, "unable to allocate FIFO name-strings\n");
  278.     exit (10);
  279.     }
  280.     sprintf (FifoMast, "%s_m", prog_id);
  281.     sprintf (FifoSlav, "%s_s", prog_id);
  282.  
  283.     FifoSink = CreatePort (NULL, 0);
  284.     if (!FifoSink)
  285.     {
  286.     fprintf (stderr, "unable to create FifoSink FIFO port\n");
  287.     exit (10);
  288.     }
  289.  
  290.     /*
  291.      *    FIFOS
  292.      */
  293.  
  294.     FifoBase = OpenLibrary ("fifo.library", 0);
  295.     if (!FifoBase)
  296.     {
  297.     fprintf (stderr, "unable to open %s\n", FIFONAME);
  298.     exit (10);
  299.     }
  300.  
  301.     FifoW = OpenFifo (FifoMast, FIFO_BUF_SIZE, FIFOF_WRITE | FIFOF_NORMAL | FIFOF_NBIO);
  302.     if (FifoW == NULL)
  303.     {
  304.     fprintf (stderr, "unable to open fifo %s\n", FifoMast);
  305.     exit (10);
  306.     }
  307.  
  308.     FifoR = OpenFifo (FifoSlav, FIFO_BUF_SIZE, FIFOF_READ  | FIFOF_NORMAL | FIFOF_NBIO);
  309.     if (FifoR == NULL)
  310.     {
  311.     fprintf (stderr, "unable to open fifo %s\n", FifoSlav);
  312.     exit (10);
  313.     }
  314.     RMsg.mn_ReplyPort = FifoSink;
  315.     WMsg.mn_ReplyPort = FifoSink;
  316.  
  317.     pmask = 1 << FifoSink->mp_SigBit;
  318. }
  319.  
  320. void close_fifo (void)
  321. {
  322.     /*
  323.     **    Shut down the pending FIFO reads/writes.
  324.     **
  325.     */
  326.     if (FifrIP)
  327.     {
  328.     if (alert_loc)
  329.         printf ("shutting down `FifrIP' (FIFO: read ? pending)\n");
  330.     RequestFifo (FifoR, &RMsg, FREQ_ABORT);
  331.     WaitMsg (&RMsg);
  332.     FifrIP = 0;
  333.     }
  334.     if (FifwIP)
  335.     {
  336.     if (alert_loc)
  337.         printf ("shutting down `FifwIP' (FIFO: write ? pending)\n");
  338.     RequestFifo (FifoW, &WMsg, FREQ_ABORT);
  339.     WaitMsg (&WMsg);
  340.     FifwIP = 0;
  341.     }
  342.  
  343.     /*
  344.     **    Shut down the FIFO read/write streams.
  345.     **
  346.     */
  347.     if (FifoR)
  348.     {
  349.     if (alert_loc)
  350.         printf ("shutting down `FifoR' (FIFO: Read stream)\n");
  351.     CloseFifo (FifoR, FIFOF_EOF);
  352.     FifoR = NULL;
  353.     }
  354.     if (FifoW)
  355.     {
  356.     if (alert_loc)
  357.         printf ("shutting down `FifoW' (FIFO: Write stream)\n");
  358.     CloseFifo (FifoW, FIFOF_EOF);
  359.     FifoW = NULL;
  360.     }
  361.  
  362.     if (FifoBase)
  363.     {
  364.     if (alert_loc)
  365.         printf ("closing FifoBase (libs:fifo.library)\n");
  366.     CloseLibrary ( (struct Library *) FifoBase);
  367.     FifoBase = NULL;    /*** DANGEROUS; should make this auto-init! ***/
  368.     }
  369.  
  370.     if (FifoSink)
  371.     {
  372.     if (alert_loc)
  373.         printf ("releasing `FifoSink' (misc. FIFO: msg. rec. port)\n");
  374.     DeletePort (FifoSink);
  375.     FifoSink = NULL;
  376.     RMsg.mn_ReplyPort = FifoSink;
  377.     WMsg.mn_ReplyPort = FifoSink;
  378.  
  379.     }
  380.     if (FifoSlav)
  381.     {
  382.     free (FifoSlav);
  383.     FifoSlav = NULL;
  384.     }
  385.     if (FifoMast)
  386.     {
  387.     free (FifoMast);
  388.     FifoMast = NULL;
  389.     }
  390.     pmask = 0;
  391. }
  392.  
  393.  
  394. void clean_up (void)
  395. {
  396.     close_fifo ();
  397.     if (win)
  398.     {
  399.     if (alert_loc)
  400.         printf ("releasing `win' (Intuition Window)\n");
  401.     CloseWindow (win);
  402.     win = NULL;
  403.     }
  404.     close_rexx ();
  405.     close_ser ();
  406. }
  407.  
  408.  
  409. void init (void)
  410. {
  411.     read_sercli_config ();
  412.     set_error_handler (error_type_serial, on_error_ser);    /*** ignore old handler??? ***/
  413.  
  414.     onbreak (do_nothing);
  415.     atexit (clean_up);
  416.     Enable_Abort = 0;
  417.  
  418.     if (alert_loc)
  419.     printf (COPYRIGHT_NOTICE);
  420.  
  421.     open_ser ();
  422.     open_rexx ();
  423.  
  424.  
  425.     {
  426.     char
  427.         buf [256];
  428.     int
  429.         len;
  430.  
  431.     if (!nether_name)
  432.         nether_name = strdup ("no user");
  433.     len = sprintf
  434.     (
  435.         buf,
  436.         "%s: with {%s} id {%s}",
  437.         PROG_NAME,
  438.         nether_name,
  439.         prog_id
  440.     );
  441.     nw.Title = window_title = strdup (buf);         /*** just use nw.Title??? ***/
  442.  
  443.     win_width = nw.Width = GADGETS_WIDTH + (len * TEXT_WIDTH);
  444.     win_height = nw.Height = TEXT_HEIGHT + 2;
  445.  
  446.     win = OpenWindow (&nw);
  447.     }
  448.  
  449.     if (!win)
  450.     exit (10);
  451.  
  452.     open_fifo ();
  453.  
  454.     imask = 1 << win->UserPort->mp_SigBit;
  455. }
  456.  
  457.  
  458. void SendBreak (int c)
  459. {
  460.     char buf [256];
  461.     long fh;
  462.  
  463.     sprintf (buf, "FIFO:%s/%c", prog_id, c);
  464.     if (fh = Open (buf, 1005))
  465.     Close (fh);
  466. }
  467.  
  468. void set_wake_flags (void)
  469. {
  470.     wake_flags
  471.     = ser_read_reply_mask
  472.     | ser_write_reply_mask
  473.     | imask
  474.     | pmask
  475.     | rexx_mask;
  476. }
  477.  
  478. void send_eof (void)
  479. {
  480.     close_fifo ();
  481.     if (alert_ser)
  482.     write_ser_str ("\n<EOF>\n");
  483.     open_fifo ();
  484.     set_wake_flags ();
  485. }
  486.  
  487. int main (int argc, char *argv [])
  488. {
  489.     char *buf;
  490.     char *o_buf;
  491.     short notDone = 1;
  492.     short online = 0;    /*** have we told FIFO to send an EOF? ***/
  493.     short carrier = 0;    /*** connected? ***/
  494.  
  495.  
  496.     buf = malloc (SER_READ_MAX);
  497.     o_buf = malloc (SER_READ_MAX);
  498.     if (!(buf && o_buf) )
  499.     {
  500.     fprintf (stderr, "Could not allocate ser<->FIFO i/o buffers.\n");
  501.     exit (10);
  502.     }
  503.  
  504.     if (argc > 1)
  505.     config_file_name = argv [1];
  506.     else
  507.     config_file_name = "sercli_config";
  508.  
  509.     init ();
  510.  
  511.     /*
  512.     **    Begin by requesting asynch i/o from our FIFO and the .device
  513.     **
  514.     */
  515.     read_ser_asynch (buf, SER_READ_MAX);
  516.     RequestFifo (FifoR, &RMsg, FREQ_RPEND);
  517.     FifrIP = 1;
  518.  
  519.     set_wake_flags ();
  520.  
  521.     while (notDone)
  522.     {
  523.     ULONG mask;
  524.     IOExtSer *ser_status;
  525.  
  526.     mask = Wait (wake_flags);
  527. top:
  528.         ser_status = query_ser ();
  529.         carrier = !(ser_status->io_Status & 32);
  530.         if (carrier != online)
  531.         {
  532. fprintf (stderr, "--  NOTICE (%s): Carrier just changed to %d\n", prog_id, carrier);
  533. //  handle_error (error_type_serial, ser_status);
  534.             if (online)
  535.             send_eof ();
  536.             online = carrier;
  537.         }
  538.  
  539.     if (mask & imask)
  540.     {
  541.         IntuiMessage *im;
  542.  
  543.         while (im = (IntuiMessage *) GetMsg (win->UserPort) )
  544.         {
  545.         switch (im->Class)
  546.         {
  547.         case CLOSEWINDOW:
  548.             notDone = 0;
  549.             if (alert_ser)
  550.             write_ser_str
  551.             (
  552.                 "\a\nLocal window shut down!\n"
  553.                 "Closing serial.device...\n"
  554.             );
  555.  
  556.             if (alert_loc)
  557.             printf
  558.             (
  559.                 "Use\n"
  560.                 "\tremcli %s\n"
  561.                 "to wrap up session.\n"
  562.                 "Or re-launch sercli without creating a new shell.\n"
  563.                 "(May not work as I make further changes...)\n"
  564.                 "(Also note that DTR should go down on exit..)\n",
  565.                 prog_id
  566.             );
  567.             break;
  568.  
  569.         default:
  570.             dput ("\nhuh?\n");
  571.             break;
  572.         }
  573.         }
  574.     }
  575.  
  576.     if (mask & ser_read_reply_mask)
  577.     {
  578.         IOExtSer *ior;
  579.  
  580.         ior = (IOExtSer *) GetMsg (ser_read_reply_port);
  581.         if (ior)
  582.         {
  583.         char c;
  584.         ULONG count;
  585.         ULONG n;
  586.         ULONG read_len;
  587.  
  588.  
  589.         read_len = ior->IOSer.io_Actual;
  590.         if (read_len)
  591.         {
  592.             ULONG data_index;
  593.  
  594.             for
  595.             (
  596.             count = 0, data_index = 0;
  597.             data_index < read_len;
  598.             ++data_index, ++count
  599.             )
  600.             {
  601.             c = buf [count];
  602.             switch (c)
  603.             {
  604.                 /*
  605.                 **    (STUPID) <CR>/<LF> conversion.
  606.                 **
  607.                 */
  608.                 case '\x0d':
  609.                 o_buf [count] = '\n';
  610.                 break;
  611.  
  612.                 /*
  613.                 **    break detection...
  614.                 **
  615.                 */
  616.                 case CTRL ('C'):
  617.                 case CTRL ('D'):
  618.                 case CTRL ('E'):
  619.                 case CTRL ('F'):
  620.                 SendBreak (CTRL (c) );
  621.                 --count;
  622.                 break;
  623.  
  624.                 /*
  625.                 **    EOF conversion
  626.                 **
  627.                 */
  628.                 case CTRL ('\\'):
  629.                 send_eof ();
  630.                 break;
  631.  
  632.                 /*
  633.                 **    standard copy operation...
  634.                 **
  635.                 */
  636.                 default:
  637.                 o_buf [count] = c;
  638.                 break;
  639.             }
  640.             }
  641.         }
  642.  
  643.         read_ser_asynch (buf, SER_READ_MAX);
  644.         if (read_len && count)
  645.             n = WriteFifo (FifoW, o_buf, count);
  646.  
  647.         /*
  648.         **  This was borrowed from remcli.c in the fifodev2.lzh
  649.         **  archive.  I've zapped it out, as it really needs
  650.         **  further adaption to work.
  651.         **
  652.         **  This shouldn't be necessary, anyway, as (hopefully)
  653.         **  only typed input will be coming in through the serial
  654.         **  port.
  655.         **
  656.         **  if (n != count)
  657.         **  {
  658.         **    ser_to_fif_p = 1;
  659.         **    if (FifwIP == 0)
  660.         **    {
  661.         **        RequestFifo (FifoW, &WMsg, FREQ_WAVAIL);
  662.         **        FifwIP = 1;
  663.         **    }
  664.         **  }
  665.         **  else
  666.         **    do next read, set pending flag.
  667.         **
  668.         */
  669.         }
  670.     }
  671.  
  672.  
  673.     if (mask & ser_write_reply_mask)
  674.         clear_write_replies ();
  675.  
  676.  
  677.     if (mask & rexx_mask)
  678.         handle_rexx ();
  679.  
  680.  
  681.     if (mask & pmask)
  682.     {
  683.         Message *msg;
  684.  
  685.         while (msg = (Message *)GetMsg (FifoSink))
  686.         {
  687.         if (msg == (Message *)&RMsg)
  688.         {
  689.             char *ptr;
  690.             long n;
  691.  
  692.             FifrIP = 0;
  693.  
  694.             if ( (n = ReadFifo (FifoR, &ptr, 0) ) > 0)
  695.             {
  696.             if (n > 256)                /*  limit size      */
  697.                 n = 256;
  698.             write_ser_asynch (ptr, n);
  699.                             /*    clear N bytes    */
  700.             n = ReadFifo (FifoR, &ptr, n);
  701.             }
  702.             if (n < 0)                      /*  EOF */
  703.             {
  704.             if (alert_ser)
  705.                 write_ser_str
  706.                 (
  707.                 "\a\nFIFO EOF!\n"
  708.                 "Closing .device...\n"
  709.                 );
  710.             notDone = 0;
  711.             }
  712.             else
  713.             {
  714.             RequestFifo (FifoR, &RMsg, FREQ_RPEND);
  715.             FifrIP = 1;
  716.             }
  717.         }
  718.         else if (msg == (Message *)&WMsg)
  719.         {
  720.             /*
  721.             **    remcli.c uses this; I don't, so this entire
  722.             **    if()...else if()... construct could be removed.
  723.             **
  724.             **    However, if it becomes a problem, I could
  725.             **    conceivably want to reinstate it for flow-control,
  726.             **    so...here it is in token form.
  727.             **
  728.             */
  729.             if (alert_ser)
  730.             write_ser_str
  731.             (
  732.                 "\nHey, a WMsg came back!\n"
  733.                 "And I didn't even send one!\n\n"
  734.             );
  735.         }
  736.         goto top;
  737.         }
  738.     }
  739.     }
  740.     return (0);
  741. }
  742.  
  743.