// C++ code Copyright (C) David R. Evans G4AMJ/NQ0I

#include <high_rate.h>
#include <DREstring.h>

// private
void phiex_position::_normalise(void)
{ while (_datum < 0)
  { _line--;
    _datum += 400;
  }
  while (_datum > 399)
  { _line++;
    _datum -= 400;
  }
}

void phiex_position::operator+=(const int data)
{ _datum += data;
  _normalise();
}

phiex_position phiex_position::operator+(const int data)
{ phiex_position rv = *this;
  rv += data;
  return rv;
}

void phiex_position::operator+=(const phiex_position& pos)
{ _datum += pos._datum;
  _line += pos._line;
  _normalise();
}

phiex_position phiex_position::operator+(const phiex_position& pos)
{ phiex_position rv = *this;
  rv += pos;
  return rv;
}

void phiex_position::operator-=(const phiex_position& pos)
{ _datum -= pos._datum;
  _line -= pos._line;
  _normalise();
}

phiex_position phiex_position::operator-(const phiex_position& pos)
{ phiex_position rv = *this;
  rv -= pos;
  return rv;
}

// constructor
phiex_frame::phiex_frame(void): _data(800, 800)
{ heap_check(_line = new octet [800]);
  heap_check(_data_pair = new octet [2]);
  heap_check(_header = new octet [1280]);
}

// constructor from file
phiex_frame::phiex_frame(char* filename) : _data(800, 800)
{ heap_check(_line = new octet [800]);
  heap_check(_data_pair = new octet [2]);
  heap_check(_header = new octet [1280]);
  read(filename);
}

// destructor
phiex_frame::~phiex_frame(void)
{ destroy_array(_header);
  destroy_array(_line);
  destroy_array(_data_pair);
}

// copy constructor
phiex_frame::phiex_frame(const phiex_frame& f) : _data(800, 800)
{ heap_check(_header = new octet [1280]);
  for (int octet_nr = 0; octet_nr < 1280; octet_nr++)
    _header[octet_nr] = f._header[octet_nr];
  
  heap_check(_line = new octet [800]);
  heap_check(_data_pair = new octet [2]);
  
  _data = f._data;

}

// return a line of data
octet* phiex_frame::line(const int line_nr)
{ for (int n = 0; n < 800; n++)
    _line[n] = _data.element(line_nr, n);
  return _line;
}

// return a pointer to a pair of data
octet* phiex_frame::data_pair(const int ln, const int dn)
{ for (int n = 0; n < 2; n++)
    _data_pair[n] = _data.element(ln, (2 * dn) + n);
  return _data_pair;
}

// 0 <= l < 800; 0 <= d < 400; 1 <= c < 3
uint16 phiex_frame::datum(const int l, const int d, const int c)
{ /* octet* temp = data_pair(l, d);
  octet temp1 = temp[c - 1];
  return temp1; */
  return (data_pair(l, d))[c - 1];
}

// read from unopened file
int phiex_frame::read(const char* filename)
{ FILE* fp = fopen(filename, "rb");
  if (!fp) then
    fatal_error((DREstring)"Unable to open file " + (DREstring)filename +
                (DREstring)" in phiex_frame::read(const char*)");

  int status = read(fp);
  fclose(fp);
  return status;
}

// read from file
int phiex_frame::read(FILE* fp)
{ TEST((uint)fread((char*)_header, 1280, 1, fp), (uint)1,
         "Cannot read header information");
  for (int n = 0; n < 800; n++)
  { if (!(n % 10)) then
      yield();
    TEST((uint)fread((char*)_line, 800, 1, fp), (uint)1,
           "Cannot read High rate data");
    for (int dn = 0; dn < 800; dn++)
      _data.element(n, dn) = _line[dn];
  }

  _swap_100_lines();
  return 1;
}

// write to a file
int phiex_frame::write(FILE* fp)
{ if (!fwrite(_header, 1280, 1, fp)) then
    return 0;

// swap octets in first 100 lines before output
  _swap_100_lines();
  
  for (int n = 0; n < 800; n++)
  { if (!fwrite(line(n), 800, 1, fp)) then
    { _swap_100_lines();
      return 0;
    }
  }

// put them back in internal order
  _swap_100_lines();
  return 1;
}

// write to an unopened file
int phiex_frame::write(const char* filename)
{ FILE* fp = fopen(filename, "w");
  if (!fp) then
    fatal_error((DREstring)"Unable to open file " + (DREstring)filename +
                (DREstring)" in phiex_frame::write(char*)");

  int status = write(fp);
  fclose(fp);
  return status;
}

// private  -- swap the octets in the first 100 lines
void phiex_frame::_swap_100_lines(void)
{ for (int n = 0; n < 100; n++)
  { line(n);
    for (int d = 0; d < 400; d++)
    { octet t = _line[2 * d];
      _line[2 * d] = _line[2 * d + 1];
      _line[2 * d + 1] = t;  
    }
  }
}

#ifdef SUN
// read from a magtape; this is based on the very ancient getgs2.for
int phiex_frame::read(magtape& tape)
{   
// Of course, JPL habitually send us tapes which are formatted
// incorrectly. Often this takes the form that there is a seperate
// _header of only 1040 octets
  if (tape.read(_header, 1280) < 1040) then
    return 0;

// the following shenanigans are necessary because of the bizarre way
// in which the data are placed on the tapes
  for (int n = 0; n < 800; n++)
  { octet temporary_buffer [1040];
    if (tape.read(temporary_buffer, 1040) < 800) then
      return 0;
    for (int octet_nr = 0; octet_nr < 800; octet_nr++)
    _line[n][octet_nr] = temporary_buffer[220 + octet_nr];
  }

// swap the first 100 lines -- internally we keep the data in freq pairs
// pairs, not polarisation pairs
  _swap_100_lines();
  return 1;
}
#endif

// return fds count
double phiex_frame::fds_count(void) const
{ return ((_header[18] << 8) + (_header[19]) +
          ((_header[20] << 8) + (_header[21])) / 100.0);
}

// return integral portion of the FDS count
uint16 phiex_frame::fds_integer(void) const
{ return ((_header[18] << 8) + (_header[19])); }

// return fractional portion of the FDS count
octet phiex_frame::fds_fraction(void) const
{ return ((_header[20] << 8) + (_header[21])); }

// return the SCET
scet_type phiex_frame::scet(void) const
{ scet_type rv;
  rv._year = _header[30] >> 1;
  rv._day = ((_header[30] & 0x1) << 8) | _header[31];
  rv._hour = (_header[32] << 8) + _header[33];
  rv._minute = rv._hour - (rv._hour / 60) * 60;
  rv._hour = rv._hour / 60;
  int16 millisecond = (_header[34] << 8) + _header[35];
  rv._second = (int16)(floor(millisecond / 1000.0));
  return rv;
}

// return spacecraft number (1 or 2)
octet phiex_frame::sc(void) const 
{ return (2 - (_header[118] & 1)); }

// merge operator -- phiex_frame + phiex_frame
void phiex_frame::operator+=(phiex_frame& f)
{ 
// calculate the averages
  int n[4], total[4], index = 0;
  
  for (int channel = 0; channel < 2; channel++)
  { for (int start_line = 0; start_line < 800;
         (start_line += 400, index++))
    { n[index] = 0;
      total[index] = 0;
      for (int line = 0; line < 400; line++)
      { if (!(line % 10)) then
          yield();
        for (int datum_nr = 0; datum_nr < 400; datum_nr++)
        { octet* data = data_pair(line + start_line, datum_nr);
          if (data[channel]) then
          { n[index]++;
            total[index] += data[channel];
          }
          data = f.data_pair(line + start_line, datum_nr);
          if (data[channel]) then
          { n[index]++;
            total[index] += data[channel];
          }
        }
      }
    }
  }

  int mean[4];

  for (index = 0; index < 4; index++)
    mean[index] = total[index] / n[index];
  index = 0;

// now do the actual merge
  for (channel = 0; channel < 2; channel++)
  { for (int start_line = 0; start_line < 800;
         (start_line += 400, index++))
    { for (int line = 0; line < 400; line++)
      { if (!(line % 10)) then
          yield();
        for (int datum_nr = 0; datum_nr < 400; datum_nr++)
        { octet* data1 = data_pair(line + start_line, datum_nr);
          const octet* data2 = f.data_pair(line + start_line, datum_nr);
          const int target = mean[index],
                    diff1 = abs(data1[channel] - target),
                    diff2 = abs(data2[channel] - target);
          if (diff2 < diff1) then
            data1[channel] = data2[channel];         
        }
      }
    }
  }
}

// merge -- not in place
phiex_frame phiex_frame::operator+(phiex_frame& f)
{ phiex_frame rv(*this);
  rv += f;
  return rv;
}

// constructor from JPL format frame
pds_phiex_frame::pds_phiex_frame(phiex_frame* pframe,
                                 const long int* c, int bw) :
                                   _bandwidth(bw),
                                   _data(800, 800)
{ phiex_frame& j = *pframe;
  for (int n = 0; n < 4; n++)
    ch[n] = c[n];
  _sc = j.sc();
  _year = j.year();
  _day = j.day();
  _hour = j.hour();
  _minute = j.minute();
  _second = j.second();
  _fds_integer = j.fds_integer();
  _fds_fraction = j.fds_fraction();
  
  _calibrate(&j);
}

// copy constructor
pds_phiex_frame::pds_phiex_frame(const pds_phiex_frame& p) : _data(800, 800)
{ for (int n = 0; n < 4; ch[n++] = p.ch[n]) ;
  _bandwidth = p._bandwidth;
  _sc = p._sc;
  _hour = p._hour;
  _minute = p._minute;
  _second = p._second;
  _fds_fraction = p._fds_fraction;
  _year = p._year;
  _day = p._day;
  _fds_integer = p._fds_integer;
  
  _data = p._data;
}

// pds_phiex_frame = pds_phiex_frame
void pds_phiex_frame::operator=(const pds_phiex_frame& p)
{ for (int n = 0; n < 4; ch[n++] = p.ch[n]) ;
  _bandwidth = p._bandwidth;
  _sc = p._sc;
  _hour = p._hour;
  _minute = p._minute;
  _second = p._second;
  _fds_fraction = p._fds_fraction;
  _year = p._year;
  _day = p._day;
  _fds_integer = p._fds_integer;
  
  _data = p._data;
}

// private -- calibration; note that we should pass const phiex frame, but this is not
// possible as the ~const syntax is not yet approved
void pds_phiex_frame::_calibrate(phiex_frame* param)
{ phiex_frame& j = *param;

  static int array[2][2][256] =
// flight unit 1
// upper
     {{{1460, 1496, 1530, 1561, 1591, 1619, 1646, 1671, 1696, 1719,
       1742, 1765, 1786, 1807, 1828, 1848, 1868, 1887, 1906, 1925,
       1943, 1961, 1979, 1997, 2014, 2032, 2049, 2066, 2082, 2099,
       2115, 2131, 2147, 2163, 2179, 2195, 2210, 2226, 2241, 2256,
       2272, 2287, 2302, 2316, 2331, 2346, 2361, 2375, 2390, 2404,
       2418, 2433, 2447, 2461, 2475, 2489, 2503, 2517, 2531, 2545,
       2558, 2572, 2586, 2599, 2613, 2626, 2640, 2653, 2667, 2680,
       2693, 2707, 2720, 2733, 2746, 2759, 2772, 2785, 2799, 2812,
       2824, 2837, 2850, 2863, 2876, 2889, 2902, 2915, 2927, 2940,
       2953, 2966, 2978, 2991, 3004, 3017, 3029, 3042, 3055, 3067,
       3080, 3093, 3105, 3118, 3131, 3144, 3156, 3169, 3182, 3194,
       3207, 3220, 3233, 3246, 3259, 3271, 3284, 3297, 3310, 3323,
       3337, 3350, 3363, 3376, 3389, 3403, 3416, 3423, 3430, 3443,
       3457, 3471, 3484, 3498, 3512, 3526, 3540, 3554, 3569, 3583,
       3598, 3612, 3627, 3642, 3657, 3672, 3688, 3703, 3719, 3734,
       3750, 3766, 3783, 3799, 3816, 3832, 3849, 3867, 3884, 3902,
       3920, 3938, 3956, 3975, 3994, 4013, 4033, 4053, 4073, 4093,
       4114, 4135, 4157, 4179, 4201, 4223, 4247, 4270, 4294, 4318,
       4343, 4368, 4394, 4420, 4447, 4474, 4502, 4530, 4559, 4588,
       4618, 4648, 4679, 4711, 4742, 4775, 4807, 4840, 4874, 4908,
       4943, 4977, 5013, 5048, 5084, 5120, 5157, 5194, 5231, 5268,
       5305, 5343, 5381, 5419, 5457, 5495, 5533, 5572, 5610, 5649,
       5687, 5726, 5764, 5803, 5841, 5880, 5918, 5957, 5995, 6034,
       6073, 6112, 6151, 6190, 6230, 6270, 6310, 6351, 6392, 6434,
       6477, 6521, 6567, 6614, 6663, 6715, 6769, 6828, 6891, 6961,
       7040, 7130, 7238, 7373, 7558, 7859},
// lower
      {1446, 1482, 1515, 1546, 1576, 1603, 1630, 1655, 1679, 1702,
       1725, 1747, 1768, 1789, 1809, 1829, 1848, 1867, 1886, 1904,
       1922, 1940, 1957, 1974, 1991, 2008, 2025, 2041, 2057, 2073,
       2089, 2105, 2121, 2136, 2151, 2167, 2182, 2197, 2212, 2226,
       2241, 2256, 2270, 2284, 2299, 2313, 2327, 2341, 2355, 2369,
       2383, 2397, 2411, 2424, 2438, 2451, 2465, 2478, 2492, 2505,
       2518, 2532, 2545, 2558, 2571, 2584, 2597, 2610, 2623, 2636,
       2649, 2662, 2675, 2688, 2701, 2713, 2726, 2739, 2751, 2764,
       2777, 2789, 2802, 2815, 2827, 2840, 2852, 2865, 2877, 2890,
       2902, 2915, 2927, 2940, 2952, 2964, 2977, 2989, 3002, 3014,
       3026, 3039, 3051, 3064, 3076, 3089, 3101, 3114, 3126, 3139,
       3151, 3164, 3176, 3189, 3201, 3214, 3227, 3239, 3252, 3265,
       3278, 3291, 3303, 3316, 3329, 3342, 3356, 3362, 3369, 3382,
       3395, 3409, 3422, 3436, 3449, 3463, 3477, 3491, 3505, 3519,
       3533, 3547, 3562, 3576, 3591, 3606, 3621, 3636, 3651, 3667,
       3682, 3698, 3714, 3730, 3746, 3762, 3779, 3796, 3813, 3830,
       3848, 3865, 3883, 3902, 3920, 3939, 3958, 3977, 3997, 4017,
       4037, 4058, 4079, 4100, 4122, 4144, 4167, 4189, 4213, 4236,
       4260, 4285, 4310, 4335, 4361, 4387, 4414, 4441, 4469, 4497,
       4526, 4555, 4584, 4614, 4645, 4676, 4707, 4739, 4771, 4803,
       4836, 4869, 4902, 4936, 4970, 5004, 5038, 5073, 5107, 5142,
       5177, 5212, 5248, 5283, 5319, 5355, 5391, 5427, 5464, 5500,
       5537, 5573, 5610, 5647, 5684, 5721, 5759, 5796, 5834, 5871,
       5909, 5947, 5985, 6024, 6063, 6102, 6141, 6181, 6222, 6264,
       6306, 6349, 6394, 6441, 6489, 6541, 6595, 6653, 6716, 6786,
       6864, 6954, 7061, 7196, 7381, 7681}},

// flight unit 2
// upper
    {{ 1435, 1480, 1523, 1563, 1600, 1636, 1670, 1702, 1734, 1764,
       1793, 1822, 1849, 1876, 1902, 1928, 1953, 1978, 2002, 2025,
       2048, 2071, 2093, 2115, 2136, 2157, 2178, 2199, 2219, 2239,
       2259, 2278, 2297, 2316, 2335, 2353, 2371, 2389, 2407, 2425,
       2442, 2459, 2477, 2493, 2510, 2527, 2543, 2560, 2576, 2592,
       2608, 2623, 2639, 2655, 2670, 2685, 2701, 2716, 2731, 2746,
       2760, 2775, 2790, 2804, 2819, 2833, 2848, 2862, 2876, 2890,
       2904, 2918, 2932, 2946, 2960, 2974, 2987, 3001, 3015, 3028,
       3042, 3055, 3069, 3082, 3095, 3109, 3122, 3135, 3149, 3162,
       3175, 3188, 3201, 3214, 3227, 3240, 3254, 3267, 3280, 3293,
       3306, 3319, 3332, 3344, 3357, 3370, 3383, 3396, 3409, 3422,
       3435, 3448, 3461, 3474, 3487, 3500, 3513, 3527, 3540, 3553,
       3566, 3579, 3593, 3606, 3619, 3633, 3646, 3653, 3660, 3673,
       3687, 3700, 3714, 3728, 3742, 3756, 3770, 3784, 3798, 3813,
       3827, 3841, 3856, 3871, 3886, 3901, 3916, 3931, 3946, 3962,
       3978, 3993, 4009, 4026, 4042, 4058, 4075, 4092, 4109, 4126,
       4144, 4162, 4180, 4198, 4216, 4235, 4254, 4273, 4293, 4313,
       4333, 4353, 4374, 4395, 4417, 4439, 4461, 4483, 4506, 4530,
       4553, 4577, 4602, 4627, 4652, 4678, 4704, 4731, 4758, 4786,
       4814, 4842, 4871, 4901, 4931, 4961, 4992, 5023, 5054, 5086,
       5119, 5151, 5184, 5218, 5252, 5286, 5321, 5355, 5391, 5426,
       5462, 5498, 5534, 5571, 5607, 5644, 5681, 5719, 5756, 5794,
       5832, 5870, 5908, 5946, 5985, 6023, 6062, 6101, 6140, 6179,
       6218, 6257, 6297, 6337, 6377, 6418, 6459, 6500, 6542, 6585,
       6628, 6673, 6719, 6767, 6816, 6868, 6923, 6982, 7046, 7116,
       7195, 7286, 7394, 7529, 7714, 8015},
// lower
     { 1630, 1667, 1701, 1733, 1763, 1791, 1818, 1844, 1869, 1893,
       1916, 1938, 1960, 1981, 2002, 2022, 2042, 2061, 2080, 2099,
       2118, 2136, 2154, 2171, 2189, 2206, 2223, 2240, 2257, 2273,
       2289, 2306, 2322, 2338, 2353, 2369, 2384, 2400, 2415, 2430,
       2445, 2460, 2475, 2490, 2505, 2519, 2534, 2548, 2563, 2577,
       2592, 2606, 2620, 2634, 2648, 2662, 2676, 2690, 2704, 2718,
       2731, 2745, 2759, 2772, 2786, 2799, 2813, 2827, 2840, 2853,
       2867, 2880, 2893, 2907, 2920, 2933, 2947, 2960, 2973, 2986,
       2999, 3012, 3025, 3039, 3052, 3065, 3078, 3091, 3104, 3117,
       3130, 3143, 3156, 3169, 3181, 3194, 3207, 3220, 3233, 3246,
       3259, 3272, 3285, 3298, 3311, 3323, 3336, 3349, 3362, 3375,
       3388, 3401, 3414, 3427, 3440, 3453, 3466, 3479, 3492, 3506,
       3519, 3532, 3545, 3558, 3572, 3585, 3599, 3605, 3612, 3626,
       3639, 3653, 3667, 3680, 3694, 3708, 3722, 3736, 3750, 3764,
       3779, 3793, 3808, 3822, 3837, 3852, 3867, 3882, 3897, 3912,
       3928, 3943, 3959, 3975, 3991, 4007, 4023, 4040, 4057, 4073,
       4091, 4108, 4125, 4143, 4161, 4179, 4198, 4216, 4235, 4255,
       4274, 4294, 4314, 4334, 4355, 4376, 4398, 4419, 4441, 4464,
       4487, 4510, 4534, 4558, 4582, 4607, 4633, 4659, 4685, 4712,
       4739, 4767, 4795, 4824, 4853, 4883, 4913, 4943, 4974, 5006,
       5038, 5070, 5103, 5136, 5169, 5203, 5237, 5271, 5306, 5341,
       5376, 5411, 5447, 5482, 5518, 5554, 5590, 5626, 5662, 5699,
       5735, 5772, 5809, 5846, 5883, 5920, 5957, 5994, 6032, 6070,
       6108, 6146, 6185, 6224, 6264, 6304, 6344, 6385, 6427, 6469,
       6513, 6557, 6603, 6651, 6701, 6753, 6808, 6867, 6931, 7001,
       7080, 7171, 7278, 7414, 7599, 7900 }}};

// we assume no attenuation
//  static int attenuation_array[8] =
//  { 0, 1500, 3000, 4500, 4500, 6000, 7500, 9000 };

// the following array adjusts for:
// low band upper & lower;
// harad upper & lower;
// polhi upper & lower
  static int misc_adjustment_array[2][6] =
  {{
// flight unit 1
   -210, 60, 50, 50, 110, 200 },
// flight unit 2
  { 210, 300, 320, 300, 70, 120 }};

  const int flight_unit = 2 - sc();

  for (int line_nr = 0; line_nr < 800; line_nr++)
  { if (!(line_nr % 10))
      yield();
    for (int pair_nr = 0; pair_nr < 400; pair_nr++)
    {
// the calibration could be done in a single (long) line, but
// the following tortuous series of instructions makes it clearer
// what is going on

      const octet* pair = j.data_pair(line_nr, pair_nr);
      
// the pair is stored internally as f1, f2. f1 is always the higher
// frequency, and thus the lower path through the receiver
      for (int n = 0; n < 2; n++)
      { octet datum = pair[n];

// an empirical fix for channel 1 since Uranus on V2

        if ((year() > 86) && (n == 0) && (line_nr < 400) && datum) then
          datum = 255 - datum;
        
        short int mb = datum ? array[flight_unit][1 - n][datum] : 0;

// assume we are in high band (i.e. 200 kHz bandwidth)
        if (mb) then
          mb += misc_adjustment_array[flight_unit][5 - n];
        _data.element(line_nr, 2 * pair_nr + n) = mb;
      }
    }
  }
}

// return the frequency corresponding to a channel number
int pds_phiex_frame::channel(int n) const
{ if ((n < 1) || (n > 4)) then
    return 0;
  return ch[n - 1];
}

// input from a stream
istream& operator>>(istream& in, pds_phiex_frame& pf)
{ in >> pf._year;
  pf._year -= 1900;
  in >> pf._day;
  int temp;
  in >> temp;
  pf._hour = temp;
  in >> temp;
  pf._minute = temp;
  in >> temp;
  pf._second = temp;
  
  in >> temp;
  pf._sc = temp;
  in >> pf._fds_integer;
  in >> temp;
  pf._fds_fraction = temp;;

  for (int n = 0; n < 4; n++)
    in >> pf.ch[n];

  in >> temp;
  pf._bandwidth = temp;
  for (int l = 0; l < 800; l++)
  { if (!(l % 10)) then
      yield();
    for (int d = 0; d < 400; d++)
    { for (int c = 1; c <= 2; c++)
       in >> pf.datum(l, d, c);
    }
  }
  return in;
}

// output to a stream (ASCII)
ostream& operator<<(ostream& out, pds_phiex_frame& pf)
{ out << (pf.year() + 1900) << " " <<
         pf.day() << " " <<
         (int)pf.hour() << " " <<
         (int)pf.minute() << " " <<
         (int)pf.second() << " " <<
         (int)pf.sc() << " " <<
         pf.fds_integer() << " " <<
         (int)pf.fds_fraction() << " ";
  for (int n = 1; n <= 4; n++)
    out << pf.channel(n) << " ";
  out << pf.bandwidth();
  out << "\n";

  for (int l = 0; l < 800; l++)
  { if (!(l % 10)) then
      yield();
    for (int d = 0; d < 400; d++)
    { for (int c = 1; c <= 2; c++)
      { out << left_fill(DREstring10(pf.datum(l, d, c)), 4) << " ";
      }
    }
    out << "\n";
  }
  return out;
}

// return a reference to a single datum; l, d wrt0, c wrt 1
/*short int& pds_phiex_frame::_ref_datum(const int l, const int d,
                                       const int c) const
{ int index = l * 800;
  index += d * 2;
  index += (c - 1);
  return data[index];
}*/

// binary write
void pds_phiex_frame::write(FILE* outfile)
{ // because of the stupid way that fwrite works, we need some dummy
  // variables

  octet dummy1;
  int16 dummy2;
  uint16 udummy2;
  int32 dummy4;

  dummy2 = year() + 1900;
  fwrite((char*)&dummy2, sizeof(dummy2), 1, outfile);
  dummy2 = day();
  fwrite((char*)&dummy2, sizeof(dummy2), 1, outfile);
  dummy1 = hour();
  fwrite((char*)&dummy1, sizeof(dummy1), 1, outfile);
  dummy1 = minute();
  fwrite((char*)&dummy1, sizeof(dummy1), 1, outfile);
  dummy1 = second();
  fwrite((char*)&dummy1, sizeof(dummy1), 1, outfile);
  dummy1 = sc();
  fwrite((char*)&dummy1, sizeof(dummy1), 1, outfile);
  udummy2 = fds_integer();
  fwrite((char*)&udummy2, sizeof(dummy2), 1, outfile);
  dummy1 = fds_fraction();
  fwrite((char*)&dummy1, sizeof(dummy1), 1, outfile);
  for (int n = 1; n <= 4; n++)
  { dummy4 = channel(n);
    fwrite((char*)&dummy4, sizeof(dummy4), 1, outfile);
  }
  dummy1 = bandwidth();
  fwrite((char*)&dummy1, sizeof(dummy1), 1, outfile);
  
  for (int l = 0; l < 800; l++)
  { if (!(l % 10)) then
      yield();
    for (int d = 0; d < 400; d++)
    { for (int c = 1; c <= 2; c++)
      { dummy2 = datum(l, d, c);
        fwrite((char*)&dummy2, sizeof(dummy2), 1, outfile);
      }
    }
  }
}

void pds_phiex_frame::read(FILE* fp)
{ /* fread(&_year, sizeof(_year), 1, fp);
  _year -= 1900;
  fread(&_day, sizeof(_day), 1, fp);
  fread(&_hour, sizeof(_hour), 1, fp);
  fread(&_minute, sizeof(_minute), 1, fp);
  fread(&_second, sizeof(_second), 1, fp);
  fread(&_sc, sizeof(_sc), 1, fp);
  fread(&_fds_integer, sizeof(_fds_integer), 1, fp);
  fread(&_fds_fraction, sizeof(_fds_fraction), 1, fp);
  fread(&(ch[0]), sizeof(uint32), 4, fp);
  fread(&_bandwidth, sizeof(_bandwidth), 1, fp); */

  read_binary(fp, _year);
  _year -= 1900;
  read_binary(fp, _day);
  read_binary(fp, _hour);
  read_binary(fp, _minute);
  read_binary(fp, _second);
  read_binary(fp, _sc);
  read_binary(fp, _fds_integer);
  read_binary(fp, _fds_fraction);
  for (int n = 0; n < 4; n++)
    read_binary(fp, ch[n]);
  read_binary(fp, _bandwidth);

  for (int l = 0; l < 800; l++)
  { if (!(l % 10)) then
      yield();

// read a line at a time for efficiency
    uint16 temp_line[800];
    if (fread(temp_line, sizeof(uint16), 800, fp) != 800) then
      fatal_error("pds_phiex_frame::read(FILE*)");

// Intel CPUs require that the data be byte swapped
#ifdef INTEL
    char* cp = (char*)temp_line;
    swab(cp, cp, 1600);
#endif

    for (int d = 0; d < 400; d++)
      for (int c = 1; c <= 2; c++)
        _data.element(l, 2 * d + c - 1) = temp_line[2 * d + c - 1];
  }
}

void pds_phiex_frame::read(const char* fn)
{ FILE* fp = fopen(fn, "rb");
  if (!fp) then
    fatal_error((DREstring)"Unable to open file " + (DREstring)fn +
                (DREstring)" in pds_phiex_frame::read(char*)");

  read(fp);
  fclose(fp);
}
