Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals  

di194.c

Go to the documentation of this file.
00001 
00024 #include "di194.h"
00025 #include "di194-internal.h"
00026 
00030 bool do_exit;
00031 
00032 
00033 // ---------------------------------------------------------------------
00050 int di_serial_close(const int COMM_FD)
00051 {
00052     if(COMM_FD > 0)
00053     {
00054         return(close(COMM_FD));
00055     }
00056     else
00057         return(-1);
00058 }
00059 
00060     
00061 // ---------------------------------------------------------------------
00082 int di_serial_init(const char *COMPORT_FILE)
00083 {
00084     char            me[] = "di_serial_init";
00085     struct termios  term;
00086     int             comm_fd = -1;
00087     const int       baud_rate = B4800;
00088         
00089     /* Open the comport, R/W access required */
00090     comm_fd = open(COMPORT_FILE, O_RDWR);
00091         
00092     /* Exit if could not open the comport */
00093     if(comm_fd < 0)
00094     {
00095         fprintf(stderr,
00096                 "\n%s: Could not open port %s\n",
00097                 me, COMPORT_FILE);
00098         perror("open");
00099         return(comm_fd);
00100     }
00101 
00102     // Read current serial flags / setup
00103     tcgetattr(comm_fd ,&term);
00104 
00105     // Control flags
00106     term.c_cflag &= ~CSIZE;
00107     term.c_cflag |= CS8;
00108     term.c_cflag |= HUPCL;
00109     term.c_cflag |= CREAD;
00110     term.c_cflag &= ~CRTSCTS;
00111     term.c_cflag |= IXON;
00112 
00113     // Output flags
00114     term.c_oflag &= ~OPOST;
00115         
00116     // Input flags
00117     term.c_iflag = IGNBRK|IGNPAR;
00118         
00119     // Que esta?
00120     term.c_lflag = 0;
00121         
00122     // Misc flags
00123     term.c_cc[VMIN] = 0;
00124     term.c_cc[VTIME] = (serial_timeout * 10);  // spec'd in deciseconds
00125 
00126     // Set input and output to 4800 baud
00127     cfsetispeed(&term, baud_rate);
00128     cfsetospeed(&term, baud_rate);
00129 
00130     /* Turn on the control lines */
00131     tcsetattr(comm_fd, TCSANOW, &term);
00132 
00133     // Wait for DI-194 to wake up?
00134     usleep(25000);
00135 
00136     /* Turn off the control lines */
00137     cfsetispeed(&term, B0);
00138     cfsetospeed(&term, B0);
00139     tcsetattr(comm_fd, TCSANOW, &term);
00140 
00141     /* Turn on the control lines */
00142     cfsetospeed(&term, baud_rate);
00143     tcsetattr(comm_fd, TCSANOW, &term);
00144 
00145     // Wait for DI-194 to wake up?
00146     usleep(25000);
00147 
00148     // Empty out any junk in the serial buffers
00149     tcflush(comm_fd, TCIOFLUSH);
00150 
00151     return(comm_fd);
00152 }
00153 
00154 // ---------------------------------------------------------------------
00171 int min(const int A, const int B)
00172 {
00173     return(A < B? A : B);
00174 }
00175 
00176 // ---------------------------------------------------------------------
00187 void hex_print_byte(const uint8_t in_byte)
00188 {
00189     printf("%02X ", (int) in_byte);
00190     if(isprint(in_byte))
00191         printf("(%c)", in_byte);
00192 }
00193 
00194 int di_stop(const int COMM_FD)
00195 {
00196     return(di_cmd_send(COMM_FD, stop_cmd, sizeof(stop_cmd)));
00197 }
00198 
00199 
00200 int di_start(const int COMM_FD)
00201 {
00202     return(di_cmd_send(COMM_FD, start_cmd, sizeof(start_cmd)));
00203 }
00204 
00205 int di_reset(const int COMM_FD)
00206 {
00207     return(di_cmd_send(COMM_FD, rst_cmd, sizeof(rst_cmd)));
00208 }
00209 
00210 int di_serial_num(const int COMM_FD, char *ser_buf)
00211 {
00212     char    me[] = "di_serial";
00213     int     rc, idx;
00214     
00215     rc = di_cmd_send(COMM_FD, sn_cmd, sizeof(sn_cmd));
00216     if(rc != 0)
00217     {
00218         fprintf(stderr,
00219                 "\nError sending serial number request, rc=%d\n", rc);
00220         return(1);
00221     }
00222 
00223     // Receive 10 bytes of serial number, or timeout
00224     rc = di_serial_read(COMM_FD, ser_buf, SERIAL_NUM_LEN, serial_timeout);
00225     if(rc != 0)
00226     {
00227         // Error, bail
00228         fprintf(stderr, "\n%s: Error reading serial number", me);
00229 
00230         if(rc >= 1)
00231         {
00232             fprintf(stderr, "\n%s: Data received was '", me);
00233             for(idx = 0; idx < rc; idx++)
00234                 fprintf(stderr, "%02X ",
00235                         (int) ser_buf[idx]);
00236             fprintf(stderr, "'\n");
00237         }
00238         return(2);
00239     }
00240     
00241     return(0);
00242 }
00243 
00244 
00245 // ---------------------------------------------------------------------  
00266 int di_serial_read(const int COMM_FD, const uint8_t *buf,
00267                    const int READ_LEN, const time_t TIMEOUT)
00268 {
00269     char       me[] = "di_serial_read";
00270     time_t     t_start;
00271     int        rc;
00272     int        rx_count = 0;
00273 
00274     t_start = time(NULL);
00275 
00276     // Read until timeout or get the data amount requested
00277     while(((time(NULL) - t_start) < TIMEOUT) &&
00278           (rx_count < READ_LEN))
00279     {
00280         // Try and get all of the remaining data at once
00281         rc = read(COMM_FD, (uint8_t *) &buf[rx_count],
00282                   (READ_LEN - rx_count));
00283         if(rc < 0)
00284         {
00285             // Read error
00286             fprintf(stderr, "\n%s: Error on read, rc=%d", me, rc);
00287             return(1);
00288         }
00289         if(rc == 0)
00290         {
00291             // No data yet, wait half a character time
00292             usleep(100);
00293         }
00294         else // rc > 0, got data
00295             rx_count += rc;
00296     }
00297 
00298     // Are we done
00299     if(rx_count >= READ_LEN)
00300         return(0);
00301     else
00302     {
00303         fprintf(stderr, "\n%s: Short read, got %d of %d expected",
00304                 me, rx_count, READ_LEN);
00305         fprintf(stderr, ", elapsed was %u seconds",
00306                 (uint32_t) (time(NULL) - t_start));
00307 
00308         if(rx_count != 0)
00309             return(rx_count);
00310         else
00311             return(-1);
00312     }
00313 }
00314 
00315 // ---------------------------------------------------------------------
00324 void di_cmd_print(const uint8_t *cmd, const int CMD_LEN)
00325 {
00326     char    me[] = "di_cmd_print";
00327     int     idx;
00328 
00329     if(CMD_LEN > 1)
00330         fprintf(stderr, "\n%s: %d-byte command '", me, CMD_LEN);
00331     else if(CMD_LEN == 1)
00332         fprintf(stderr, "\n%s: 1-byte argument '", me);
00333     else
00334     {
00335         fprintf(stderr, "\n%s: Error, invalid cmd length %d",
00336                 me, CMD_LEN);
00337         return;
00338     }
00339                         
00340     for(idx = 0; idx < CMD_LEN; idx++)
00341     {
00342         fprintf(stderr, " %02X", (int) cmd[idx]);
00343                 
00344         if(isprint(cmd[idx]))
00345             fprintf(stderr, " (%c)", cmd[idx]);
00346     }
00347 
00348     fprintf(stderr, "'");
00349     return;
00350 }
00351 
00352 // ---------------------------------------------------------------------
00375 bool is_reset_cmd(const uint8_t *cmd, const int CMD_LEN)
00376 {
00377     char    me[] = "is_reset_cmd";
00378     int     idx;
00379 
00380     // Simple checks
00381     if((CMD_LEN != 3) || (cmd == NULL))
00382         return(false);
00383 
00384     for(idx = 0; idx < CMD_LEN; idx++)
00385         if(cmd[idx] != rst_cmd[idx])
00386             return(false);
00387         
00388     return(true);
00389 
00390     // intentionally unreachable code
00391     fprintf(stderr, "\n%s: Reset command found", me);
00392 }
00393 
00394 // ---------------------------------------------------------------------
00417 int di_daq_sync(const int COMM_FD)
00418 {
00419     char            me[] = "di_daq_sync";
00420     uint8_t         sync_buf[5 * sizeof(daq_buf_t)] = "";
00421     int             idx, rc, clear_count;
00422     bool            found_match = false;
00423 
00424         
00425     // Get three samples' worth of serial data, plus slop
00426     rc = di_serial_read(COMM_FD, sync_buf, (4 * sizeof(daq_buf_t)),
00427                         serial_timeout);
00428     if(rc != 0)
00429     {
00430         fprintf(stderr, "\n%s: Error reading\n", me);
00431         return(rc);
00432     }
00433 
00434     // Scan for pattern match
00435     for(idx = 0; idx < (3 * sizeof(daq_buf_t)); idx++)
00436     {
00437         rc = di_buf_validate(&sync_buf[idx]);
00438         if(rc != 0)
00439             fprintf(stderr, "\n%s: No sync at index %d, rc %d", me, idx, rc);
00440         else
00441         {
00442           //        fprintf(stderr, "\n%s: Sync at index %d", me, idx);
00443             found_match = true;
00444             break;
00445         }
00446     }
00447 
00448     if(found_match == true)
00449     {
00450         // Figure how many to read to sync up
00451         clear_count = idx;
00452 
00453         rc = di_serial_read(COMM_FD, sync_buf,
00454                             clear_count, serial_timeout);
00455         if(rc != 0)
00456         {
00457             fprintf(stderr, "\n%s: Error on sync read!", me);
00458             return(rc);
00459         }
00460                 
00461         // Check again?
00462         return(0);
00463     }
00464     else
00465         fprintf(stderr, "\nNo sync\n");
00466     
00467     // Failed, do nothing else
00468     return(-1);
00469 }
00470                 
00471 
00472 // ---------------------------------------------------------------------
00502 int di_cmd_send(const int COMM_FD, const uint8_t *cmd, const int CMD_LEN)
00503 {
00504     char     me[] = "di_cmd_send";
00505     int      idx, rc;
00506     uint8_t  btmp;
00507     int      read_len = CMD_LEN;
00508 
00509     if(cmd == NULL)
00510         return(-1);
00511 
00512     // DDT print to screen what command is
00513     // di_cmd_print(cmd, CMD_LEN);
00514         
00515     // Reset is annoyingly different
00516     //    if(is_reset_cmd(cmd, CMD_LEN))
00517     //  read_len++;
00518 
00519     for(idx = 0; idx < CMD_LEN; idx++)
00520     {
00521         // Send one byte (cmd or argument)
00522         rc = write(COMM_FD, &cmd[idx], sizeof(uint8_t));
00523         if(rc != sizeof(uint8_t))
00524         {
00525             fprintf(stderr, "\n%s: Error sending command", me);
00526             return(1);
00527         }
00528                 
00529         // Zeros (NULLS) precede each cmd and are never echoed back
00530         if(cmd[idx] == 0x00)
00531             continue;
00532     
00533         // Look for the echo back, just one character
00534         rc = di_serial_read(COMM_FD, &btmp,
00535                             sizeof(btmp), serial_timeout);
00536         if(rc != 0)
00537         {
00538             fprintf(stderr, "\n%s: Error on command echo read",
00539                     me);
00540             return(2);
00541         }
00542         // DDT check echo
00543         if(btmp != cmd[idx])
00544         {
00545             fprintf(stderr, "\n%s: Cmd was %02X, echo was %02X",
00546                     me, (int) cmd[idx], (int) btmp);
00547         }
00548         /*
00549                         else
00550                         fprintf(stderr, "\n%s: Cmd was %02X, echo was same",
00551                         me, (int) cmd[idx]);
00552         */
00553     }
00554 
00555     // Any left to read?
00556     for(idx = 0; idx < (read_len - CMD_LEN); idx++)
00557     {
00558         rc = di_serial_read(COMM_FD, &btmp,
00559                             sizeof(btmp), serial_timeout);
00560         if(rc != 0)
00561         {
00562             fprintf(stderr, "\n%s: Error reading trailer bytes\n",
00563                     me);
00564         }
00565     }
00566 
00567     return(0);
00568 }
00569                 
00570 // ---------------------------------------------------------------------
00589 int di_initialize(const int COMM_FD, int *num_bits)
00590 {
00591     char          me[] = "di_initialize";
00592     int           idx, rc;
00593     uint8_t       ser_buf[SERIAL_NUM_LEN * 2] = "";
00594     const uint8_t rs_signature[SERIAL_NUM_LEN + 1] = "0000000000";
00595 
00596     
00597     // DDT, one extra byte (0xFF) from 194RS
00598     read(COMM_FD, ser_buf, 1);
00599 
00600     // Unknown init cmd, ignore return code for now
00601     di_cmd_send(COMM_FD, odd_cmd, sizeof(odd_cmd));
00602 
00603     // Stop acquiring data
00604     rc = di_stop(COMM_FD);
00605         
00606     // Try requesting the serial number to check presence
00607     rc = di_serial_num(COMM_FD, ser_buf);
00608     if(rc != 0)
00609         return(rc);
00610 
00611     // New units (RS) return a serial of all ASCII zeros
00612     if(strncmp(ser_buf, rs_signature, SERIAL_NUM_LEN) == 0)
00613     {
00614         printf("\nNew (RS) unit found, skipping enable code download");
00615         *num_bits = 10;
00616     }
00617     else
00618     {
00619       *num_bits = 8;
00620       printf("\nDI-194 found, Serial number: '");
00621 
00622         for(idx = 0; idx < SERIAL_NUM_LEN; idx++)
00623             printf("%c", ser_buf[idx]);
00624         printf("'\nSending enable key to device");
00625 
00626         // Send the key (enabler) out
00627         // Each key byte is prefixed with 0x00 0x45
00628         for(idx = 0; idx < sizeof(di_enable_key); idx++)
00629         {
00630             rc = di_cmd_send(COMM_FD, key_cmd, sizeof(key_cmd));
00631             if(rc != 0)
00632             {
00633                 fprintf(stderr, "\n%s: Error sending key command", me);
00634                 return(2);
00635             }
00636 
00637             // That was key prefix, now the key byte itself
00638             rc = di_cmd_send(COMM_FD, &di_enable_key[idx], sizeof(uint8_t));
00639             if(rc != 0)
00640             {
00641                 fprintf(stderr, "\n%s: Error sending key byte", me);
00642                 return(2);
00643             }
00644         }
00645     }
00646     
00647     return(0);
00648 }
00649 
00650 
00651 // ---------------------------------------------------------------------
00676 int di_configure(const int COMM_FD)
00677 {
00678     char      me[] = "di_configure";
00679     int       rc;
00680         
00681     if(COMM_FD <= 0)
00682     {
00683         fprintf(stderr, "\n%s: Invalid file descriptor %d",
00684                 me, COMM_FD);
00685         return(1);
00686     }
00687 
00688     // Select all (analog) channels
00689     rc = di_cmd_send(COMM_FD, all_chan, sizeof(all_chan));
00690     if(rc != 0)
00691     {
00692         fprintf(stderr, "\n%s: Error sending all-channels command",
00693                 me);
00694         return(2);
00695     }
00696 
00697     // Turn on digital inputs, too
00698     rc = di_cmd_send(COMM_FD, dig_chan, sizeof(dig_chan));
00699     if(rc != 0)
00700     {
00701         fprintf(stderr,
00702                 "\n%s: Error sending digital channels command", me);
00703         return(2);
00704     }
00705 
00706     // Made it!
00707     return(0);
00708 }
00709 
00710 // ---------------------------------------------------------------------
00726 char *di_byte_print(const uint8_t in_byte)
00727 {
00728     int         idx;
00729     static char out_buf[sizeof(uint8_t) * sizeof(char) + 1];
00730     uint8_t     btmp;
00731 
00732 
00733     for(idx = 0; idx < 8; idx++)
00734     {
00735         // Slice off MSB
00736         btmp = ((in_byte >> (7 - idx)) & 0x01);
00737         // Convert to ASCII
00738         out_buf[idx] = (btmp + '0');
00739     }
00740 
00741     return(out_buf);
00742 }
00743 
00744 // ---------------------------------------------------------------------
00770 int di_buf_validate(const daq_buf_t buf)
00771 {
00772   int idx;
00773 
00774   // Initial byte has trailing zero
00775   if((buf[0] & 0x01) != 0x00)
00776     return(1);
00777 
00778   // rest are constant 1
00779   for(idx = 1; idx < 8; idx++)
00780     if((buf[idx] & 0x01) != 0x01)
00781       return(idx + 1);
00782 
00783     return(0);
00784 }
00785 
00786 // ---------------------------------------------------------------------
00818 int di_buf_decode(const daq_buf_t buf, 
00819                   daq_reading_t *result, const int NUM_BITS)
00820 {
00821     uint16_t   atmp[4];
00822     int        idx;
00823     double     slope = 20.0 / ((double) (1 << NUM_BITS));
00824 
00825     if((buf == NULL) || (result == NULL))
00826         return(-1);
00827 
00828     // Check for signature
00829     if(di_buf_validate(buf) == 0)
00830     {
00831         result->is_valid = true;
00832     }
00833     else
00834     {
00835         result->is_valid = false;
00836             
00837         printf("\nSignature not found; invalid buffer: '");
00838         for(idx = 0; idx < sizeof(daq_buf_t); idx++)
00839           hex_print_byte(buf[idx]);
00840         printf("'\n");
00841         return(1);
00842     }
00843 
00844     /*
00845       This bit-mangling won't make sense until you stare at the
00846       vendor-supplied decode table. Obfuscated data, basically.
00847 
00848       The digital-to-voltage conversion is simple: 0x00 == -10VDC,
00849       and 0xFF means +10VDC. This is just an mx+b conversion.
00850     */
00851     if(NUM_BITS == 10) // DI-194RS
00852     {
00853       atmp[0] = (((buf[1] & 0xFE) << 8) | ((buf[0] & 0xF0) >> 5)) >> 6;
00854       atmp[1] = (((buf[3] & 0xFE) << 8) | ((buf[2] & 0xF0) >> 5)) >> 6;
00855       atmp[2] = (((buf[5] & 0xFE) << 8) | ((buf[4] & 0xF0) >> 5)) >> 6;
00856       atmp[3] = (((buf[7] & 0xFE) << 8) | ((buf[6] & 0xF0) >> 5)) >> 6;
00857       
00858       for(idx = 0; idx < 4; idx++)
00859       {
00860         result->analog[idx] = -10.0 + (slope * (atmp[idx]));
00861         result->raw[idx] = atmp[idx];
00862       }
00863       
00864       
00865       // In 240 Hz mode, we get 4 different reads on the digital!
00866       result->digital[0] = (buf[2] & 0x08) ? 1 : 0;
00867       result->digital[1] = (buf[2] & 0x04) ? 1 : 0;
00868       result->digital[2] = (buf[2] & 0x02) ? 1 : 0;
00869       
00870     }
00871     else if(NUM_BITS == 8)
00872     {
00873       atmp[0] = (((buf[1] & 0xFE) << 8) | ((buf[0] & 0xF0) >> 7)) >> 8;
00874       atmp[1] = (((buf[3] & 0xFE) << 8) | ((buf[2] & 0xF0) >> 7)) >> 8;
00875       atmp[2] = (((buf[5] & 0xFE) << 8) | ((buf[4] & 0xF0) >> 7)) >> 8;
00876       atmp[3] = (((buf[7] & 0xFE) << 8) | ((buf[6] & 0xF0) >> 7)) >> 8;
00877       
00878       for(idx = 0; idx < 4; idx++)
00879       {
00880         result->analog[idx] = -10.0 + (slope * (atmp[idx]));
00881         result->raw[idx] = atmp[idx];
00882       }
00883       
00884 
00885       // In 240 Hz mode, we get 4 different reads on the digital!
00886       result->digital[0] = (buf[0] & 0x08) ? 1 : 0;
00887       result->digital[1] = (buf[0] & 0x04) ? 1 : 0;
00888       result->digital[2] = (buf[0] & 0x02) ? 1 : 0;
00889     }
00890 
00891     return(0);
00892 }
00893 
00894 //***********************************************************************
00914 int di_open(const char *COMPORT_FILE, int *num_bits)
00915 {
00916     char          me[] = "di_open";
00917     int           rc;
00918     char          *portname = NULL;
00919     const char    com1[] = "/dev/ttyS0"; // Default serial port
00920     int           comm_fd = -1;
00921 
00922     // If no port passed, try environment or default
00923     if(COMPORT_FILE == NULL)
00924     {
00925         // If set, use environment variable
00926         portname = getenv("DI194_PORT");
00927         if(portname == NULL)
00928         {
00929             // Fallback to hardwired serial port zero
00930             portname = (char *) com1;
00931         }
00932     }
00933     else // try users' port
00934         portname = (char *) COMPORT_FILE;
00935         
00936     /* Try to open connection to desired comport */
00937     //    printf("\nOpening serial port '%s'", portname);
00938     //    fflush(stdout);
00939 
00940     comm_fd = di_serial_init(portname);
00941     if(comm_fd < 0)
00942     {
00943         fprintf(stderr, "\n%s: Error opening port '%s'",
00944                 me, portname);
00945         return(-1);
00946     }
00947 
00948     //   printf("\nPort opened OK, initializing and reading serial number...");
00949     //   fflush(stdout);
00950         
00951     // pfh use my init and read serial code, precision
00952     rc = di_initialize(comm_fd, num_bits);
00953     if(rc != 0)
00954     {
00955         fprintf(stderr, "\n%s: Error initializing device\n", me);
00956         return(-2);
00957     }
00958 
00959     //    printf("\nUnit opened OK, programming...");
00960     //    fflush(stdout);
00961 
00962     // Set the DAQ up (programming constant DAQ)
00963     rc = di_configure(comm_fd);
00964     if(rc != 0)
00965     {
00966         fprintf(stderr, "\n%s: Error programming device\n", me);
00967         return(-3);
00968     }
00969 
00970     // Hmm. 
00971     return(comm_fd);
00972 }
00973 
00974 //***********************************************************************
00988 int di_close(const int COMM_FD)
00989 {
00990     char       me[] = "di_close";
00991     int        rc;
00992     
00993     rc = di_serial_close(COMM_FD);
00994 
00995     if(rc != 0)
00996         fprintf(stderr, "\n%s: Error %d closing DI-194 port\n",
00997                 me, rc);
00998     
00999     return(rc);
01000 }
01001 
01002 
01003 //***********************************************************************
01021 int di_read(const int COMM_FD, daq_reading_t *data, const int NUM_BITS)
01022 {
01023     char          me[] = "di_read";
01024     int           rc;
01025     daq_buf_t     raw_buf;
01026     
01027 
01028     // Single DAQ
01029     rc = di_serial_read(COMM_FD, raw_buf,
01030                         sizeof(raw_buf), serial_timeout);
01031     if(rc != 0)
01032     {
01033         fprintf(stderr, "\n%s: Error %d on serial read",
01034                 me, rc);
01035         return(rc);
01036     }
01037     
01038     // decode buffer
01039     rc = di_buf_decode(raw_buf, data, NUM_BITS);
01040     if(rc != 0)
01041     {
01042         fprintf(stderr, "\n%s: Error %d on buffer decode; overflow?",
01043                 me, rc);
01044         
01045         return(rc);
01046     }
01047 
01048     // DDT
01049     /*
01050     printf("\n");
01051     for(idx = 0; idx < 8; idx++)
01052       hex_print_byte(raw_buf[idx]);
01053     printf("\n");
01054     */
01055     // Made it!
01056     return(0);
01057 }
01058 
01059 //***********************************************************************
01077 int di_read_single(const int COMM_FD, daq_reading_t *data, const int NUM_BITS)
01078 {
01079     int      rc;
01080 
01081 
01082     // Start DAQ
01083     rc = di_start(COMM_FD);
01084     if(rc != 0)
01085         return(rc);
01086     
01087     rc = di_read(COMM_FD, data, NUM_BITS);
01088     if(rc != 0)
01089     {
01090         di_stop(COMM_FD);
01091         return(rc);
01092     }
01093     
01094     rc = di_stop(COMM_FD);
01095 
01096     return(rc);
01097 }
01098 

Generated on Thu May 1 11:31:45 2003 for DI-194 driver by doxygen1.3