home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1993 May / SIMTEL_0593.ISO / msdos / hamradio / icom.c < prev    next >
C/C++ Source or Header  |  1987-11-15  |  9KB  |  436 lines

  1. 15-Nov-87 22:41:42-MST,9407;000000000000
  2. Date: Thursday, 21 August 1986  01:45-MDT
  3. From: Phil Karn <karn at ka9q.bellcore.COM>
  4. To:   info-hams
  5. Re:   Controlling ICOM radios from the IBM PC - Part 2 (source code)
  6.  
  7. Here's the source code I wrote for controlling the ICOM radios through my PC
  8. clone's printer port. Note that all frequencies are represented in hertz,
  9. using longs; this makes things more consistent since different radio functions
  10. require different precision.
  11.  
  12. -----------
  13. /* icom.c
  14.  * Library functions for driving the ICOM computer interface
  15.  * Copyright 1986 by Phil Karn, KA9Q
  16.  * Permission granted for free noncommercial copying and use by
  17.  * licensed radio amateurs.
  18.  */
  19. #include "icom.h"
  20.  
  21. char *modes[] = {
  22. "LSB",    /* 0 */
  23. "USB",    /* 1 */
  24. "AM",    /* 2 */
  25. "CW",    /* 3 */
  26. "RTTY",    /* 4 */
  27. "FM",    /* 5 */
  28. "CW Narrow",    /* 6 */
  29. "RTTY Narrow",    /* 7 */
  30. "lsb",    /* 8 */
  31. "usb",    /* 9 */
  32. "am",    /* a */
  33. "cw narrow",    /* b */
  34. "rtty narrow",    /* c */
  35. "fm",    /* d */
  36. "0xe",    /* e */
  37. "0xf"    /* f */
  38. };
  39.  
  40. /* Read band */
  41. int
  42. read_band(freq,lower,upper)
  43. long freq;        /* Used just to select the radio */
  44. long *lower,*upper;    /* Band limits returned through here */
  45. {
  46.     register int i;
  47.  
  48.     start_cmd();
  49.     if(send_byte(BAND | band(freq)) < 0){
  50.         end_cmd();
  51.         return -1;
  52.     }
  53.     *upper = 0;
  54.     read_byte();        /* Toss opening delim */
  55.     for(i=0;i<6;i++)
  56.         *upper = *upper * 10 + (read_byte() & 0xf);
  57.     read_byte();        /* Toss closing delim */
  58.     *upper *= 10000;    /* Convert to hertz */
  59.  
  60.     *lower = 0;
  61.     read_byte();        /* Toss second opening delim */
  62.     for(i=0;i<6;i++)
  63.         *lower = *lower * 10 + (read_byte() & 0xf);
  64.     read_byte();        /* Toss second closing delim */
  65.     *lower *= 10000;    /* Convert to hertz */    
  66.     end_cmd();
  67.     return 0;
  68. }
  69. /* Set frequency; the proper radio is automatically selected */
  70. int
  71. set_freq(freq)
  72. long freq;    /* Frequency, hertz */
  73. {
  74.     register int i;
  75.     char fstr[15];
  76.  
  77.     start_cmd();
  78.     if(send_byte(FREQ | band(freq)) < 0){
  79.         end_cmd();
  80.         return -1;
  81.     }
  82.     send_byte(FREQ | 0xd);
  83.     sprintf(fstr,"%09ld",freq/10);
  84.     for(i=0;i<9;i++)
  85.         send_byte(FREQ | (fstr[i] - '0'));
  86.     send_byte(FREQ | 0xe);
  87.     end_cmd();
  88.     return 0;
  89. }
  90.  
  91. /* Read frequency */
  92. long
  93. read_freq(freq)
  94. long freq;    /* For band selection only */
  95. {
  96.     register int i;
  97.  
  98.     start_cmd();
  99.     if(send_byte(FREQ | band(freq)) < 0){
  100.         end_cmd();
  101.         return -1;
  102.     }
  103.     if(read_byte() < 0)     /* Discard opening delimiter */
  104.         return -1;
  105.     freq = 0;
  106.     for(i=0;i<9;i++){
  107.         freq = freq * 10 + (read_byte() & 0xf);
  108.     }
  109.     read_byte();        /* Discard closing delimiter */
  110.     freq *= 10;
  111.     end_cmd();
  112.     return freq;
  113. }
  114. /* set mode */
  115. int
  116. set_mode(freq,mode)
  117. long freq;        /* For radio selection */
  118. int mode;        /* Desired operating mode */
  119. {
  120.     start_cmd();
  121.     if(send_byte(MODE | band(freq)) < 0){
  122.         end_cmd();
  123.         return -1;
  124.     }
  125.     send_byte(MODE | 0xd);
  126.     send_byte(MODE | mode);
  127.     send_byte(MODE | 0xe);
  128.     end_cmd();
  129.     return 0;
  130. }
  131. /* Return current mode */
  132. int
  133. read_mode(freq)
  134. long freq;        /* For radio selection */
  135. {
  136.     int c;
  137.  
  138.     start_cmd();
  139.     if(send_byte(MODE | band(freq)) < 0){
  140.         end_cmd();
  141.         return -1;
  142.     }
  143.     read_byte();
  144.     c = read_byte();
  145.     read_byte();
  146.     end_cmd();
  147.     return c & 0xf;
  148. }
  149. /* Set offset */
  150. int
  151. set_offset(freq,offset)
  152. long freq;    /* For radio selection */
  153. long offset;    /* Offset, hertz */
  154. {
  155.     register int i;
  156.     char fstr[15];
  157.  
  158.     start_cmd();
  159.     if(send_byte(OFFSET | band(freq)) < 0){
  160.         end_cmd();
  161.         return -1;
  162.     }
  163.     send_byte(OFFSET | 0xd);
  164.     sprintf(fstr,"%09ld",freq/1000);
  165.     for(i=0;i<9;i++)
  166.         send_byte(OFFSET | (fstr[i] - '0'));
  167.     send_byte(OFFSET | 0xe);
  168.     end_cmd();
  169.     return 0;
  170. }
  171.  
  172. /* Read offset */
  173. long
  174. read_offset(freq)
  175. long freq;    /* For radio selection */
  176. {
  177.     register int i;
  178.     long offset;
  179.     
  180.     start_cmd();
  181.     if(send_byte(OFFSET | band(freq)) < 0){
  182.         end_cmd();
  183.         return -1;
  184.     }
  185.     read_byte();     /* Discard opening delimiter */
  186.     offset = 0;
  187.     for(i=0;i<9;i++)
  188.         offset = offset * 10 + (read_byte() & 0xf);
  189.     read_byte();    /* Discard closing delimiter */
  190.     offset *= 1000;
  191.     end_cmd();
  192.     return offset;
  193. }
  194. /* Select memory channel or vfo */
  195. int
  196. set_mem(freq,val)
  197. long freq;        /* For radio selection */
  198. int val;        /* Desired VFO/channel number */
  199. {
  200.     start_cmd();
  201.     if(send_byte(MEMVFO | band(freq)) < 0){
  202.         end_cmd();
  203.         return -1;
  204.     }
  205.     send_byte(MEMVFO | 0xd);
  206.     send_byte(MEMVFO | ((val >> 4) & 0xf));    /* tens digit */
  207.     send_byte(MEMVFO | (val & 0xf));    /* units digit */
  208.     send_byte(MEMVFO | 0xe);
  209.     end_cmd();
  210.     return 0;
  211. }
  212. /* Transfer between VFO and memory */
  213. int
  214. transfer(freq,dir)
  215. long freq;        /* For radio selection */
  216. int dir;        /* Desired direction of transfer */
  217. {
  218.     start_cmd();
  219.     if(send_byte(MEMRW | band(freq)) < 0){
  220.         end_cmd();
  221.         return -1;
  222.     }
  223.     send_byte(MEMRW | 0xd);
  224.     send_byte(MEMRW | dir);
  225.     send_byte(MEMRW | 0xe);
  226.     end_cmd();
  227.     return 0;
  228. }
  229. /* Set band
  230.  * Uses the hack by NG6Q in April 1986 Ham Radio
  231.  * Warning: untested (I don't have a 751).
  232.  */
  233. int
  234. set_band(freq,b)
  235. long freq;        /* For radio selection */
  236. int b;            /* Desired band */
  237. {
  238.     long funny;
  239.  
  240.     set_mem(freq,38);    /* Select channel 38 */
  241.     funny = (freq/1000000) * 1000000;    /* Truncate to Mhz */
  242.     funny += 100000 * b;        /* Desired band goes in 100khz digit*/
  243.     set_freq(funny);
  244.     transfer(freq,WRITE);        /* Store in memory */
  245.     set_mem(freq,0);        /* Go back to VFO */
  246.     transfer(freq,READ);        /* Get the funny value */
  247.     set_freq(freq);            /* Put in the one we really want */
  248.     return 0;
  249. }
  250.  
  251. /* The following are internal subroutines that perform the low-level
  252.  * parts of the host/radio protocol. These can be "static" if you wish.
  253.  */
  254.  
  255. /* Send individual byte of a message */
  256. int
  257. send_byte(c)
  258. char c;
  259. {    
  260.     register int i;
  261.  
  262.     outportb(I_DATA,c);
  263.  
  264.     /* Turn on WP and output mode in addition to SRQ */
  265.     outportb(I_CTL,CTL_POL^(SRQ_CMD|WP_CMD|OUTPUT_MODE));
  266.  
  267.     /* Wait for DAV to go active low */
  268.     for(i=TIMEOUT;i != 0;i--){
  269.         if((inportb(I_DAV) & DAV_STAT) == 0)
  270.             break;
  271.     }
  272.     if(i == 0){
  273.         outportb(I_CTL,CTL_POL);
  274.         printf("sendbyte fail\n");
  275.         return -1;
  276.     }
  277.     /* Drop WP and output mode, keeping SRQ active */
  278.     outportb(I_CTL,CTL_POL^SRQ_CMD);
  279.  
  280.     /* Wait for DAV to go inactive high */
  281.     for(i=TIMEOUT;i != 0;i--){
  282.         if((inportb(I_DAV) & DAV_STAT) != 0)
  283.             break;
  284.     }        
  285.     if(i == 0){
  286.         outportb(I_CTL,CTL_POL);
  287.         printf("sendbyte fail 2\n");
  288.         return -2;
  289.     }
  290.     return 0;
  291. }
  292.  
  293. /* Read individual byte within a message */
  294. int
  295. read_byte()
  296. {
  297.     register int i;
  298.     register int c;
  299.  
  300.     /* Configure for input */
  301.     outportb(I_CTL,CTL_POL^(RP_CMD|SRQ_CMD));
  302.  
  303.     /* Wait for DAV to go active low */
  304.     for(i=TIMEOUT;i != 0;i--){
  305.         if((inportb(I_DAV) & DAV_STAT) == 0)
  306.             break;
  307.     }
  308.     if(i == 0){
  309.         outportb(I_CTL,CTL_POL);
  310.         printf("read fail\n");
  311.         return -1;
  312.     }
  313.     /* Read data byte from bus */
  314.     c = inportb(I_DATA);
  315.  
  316.     /* Drop RP, keeping SRQ active */
  317.     outportb(I_CTL,CTL_POL^SRQ_CMD);
  318.  
  319.     /* Wait for DAV to go inactive high */
  320.     for(i=TIMEOUT;i != 0;i--){
  321.         if((inportb(I_DAV) & DAV_STAT) != 0)
  322.             break;
  323.     }        
  324.     if(i == 0){
  325.         outportb(I_CTL,CTL_POL);
  326.         printf("read fail 2\n");
  327.         return -2;
  328.     }
  329.     return c & 0xff;
  330. }
  331. /* Derive band number from frequency */
  332. int
  333. band(freq)
  334. register long freq;
  335. {
  336.     if(freq >= 1200000000){
  337.         return MHZ_1200;
  338.     } else if(freq >= 420000000){
  339.         return MHZ_430;
  340.     } else if(freq >= 220000000){
  341.         return MHZ_220;
  342.     } else if(freq >= 140000000){
  343.         return MHZ_144;
  344.     } else if(freq >= 50000000){
  345.         return MHZ_50;
  346.     } else
  347.         return HF;
  348. }
  349. /* Begin a message */
  350. start_cmd()
  351. {
  352.     /* Assert SRQ */
  353.     outportb(I_CTL,CTL_POL^SRQ_CMD);
  354. }
  355. /* End a message */
  356. end_cmd()
  357. {
  358.     register int i;
  359.  
  360.     /* Wait a little bit */
  361.     for(i=WAIT;i != 0;i--)
  362.         ;
  363.     /* Deactivate SRQ */
  364.     outportb(I_CTL,CTL_POL);
  365. }
  366. -----------------
  367. /* icom.h
  368.  * Definitions for the ICOM library functions
  369.  * 21 Aug 1986
  370.  * Phil Karn, KA9Q
  371.  */
  372.  
  373. /* System-dependent constants; edit to taste */
  374.  
  375. /* Port addresses */
  376. #define    I_DATA        0x3bc    /* Data I/O port */
  377. #define    I_CTL        0x3be    /* Control port (output) */
  378. #define    I_DAV        0x3bd    /* Data available port (input) */
  379.  
  380. /* Bits within I_DAV */
  381. #define    DAV_STAT    0x40
  382. #define    DAV_POL        0x40    /* DAV is negative polarity */
  383.  
  384. /* Bits within I_CTL */
  385. #define    OUTPUT_MODE    0x20
  386. #define    RP_CMD        0x8
  387. #define    WP_CMD        0x2
  388. #define    SRQ_CMD        0x1
  389. /* Specify any bits in I_CTL which are negative logic.
  390.  * Output mode, RP and WP are negative logic; SRQ is positive
  391.  */
  392. #define    CTL_POL    (OUTPUT_MODE|RP_CMD|WP_CMD)
  393.  
  394. /* These two values were found experimentally to work on an 8-MHz 8088
  395.  * Increase WAIT if you get frequent timeouts or protocol lockups
  396.  */
  397. #define    TIMEOUT    65535    /* Timeout on a read/write operation */
  398. #define    WAIT    1100    /* Delay at end of sequence */
  399.  
  400. /* The following definitions are fixed by the ICOM design; they should not
  401.  * have to be changed.
  402.  */
  403.  
  404. /* Commands */
  405. #define    BAND        0x10
  406. #define    FREQ        0x20
  407. #define    MODE        0x30
  408. #define    OFFSET        0x40
  409. #define    MEMVFO        0x50
  410. #define    MEMRW        0x60
  411.  
  412. /* Addresses */
  413. #define    HF        0x1    /* IC-71 or IC-751 */
  414. #define    MHZ_50        0x2
  415. #define    MHZ_144        0x3    /* IC-271 */
  416. #define    MHZ_220        0x4
  417. #define    MHZ_430        0x5    /* IC-471 */
  418. #define    MHZ_1200    0x6    /* IC-1271 */
  419.  
  420. /* Modes */
  421. #define    LSB    0
  422. #define    USB    1
  423. #define    AM    2
  424. #define    CW    3
  425. #define    RTTY    4
  426. #define    FM    5
  427. #define    CWN    6
  428. #define    RTTYN    7
  429.  
  430. #define    WRITE    1    /* VFO to memory */
  431. #define    READ    2    /* Memory to VFO */
  432.  
  433. long read_freq();
  434. --------------
  435. End of code
  436.