//============================================================================================
//      vaux_std.c            ver 8.0.0.0   (7/21/08)
//
//      copyright (c) 2001-2008 Vaux Electronics, Inc.
//============================================================================================


//============================================================================================
//
//  Public routine init_random_2K_seed(random_seed) inits seed for the 2K-length sequence random
//  numbers by limiting seed and loading the 16-bit global ran_int16.  The seed must be < 0x0800.
//  This seed value starts the sequence.
//
//  Public routine init_random_32K_seed(random_seed) inits seed for the 32K-length sequence random
//  numbers by limiting seed and loading the 32-bit global ran_int32.  The seed must be < 0x8000.
//  This seed value starts the sequence.
//
//  Public routine b=random8_2K() returns a randomized int8 (byte) that is taken from
//  a randomized portion of the 16-bit global word ran_int16.  Small and fast.
//  An initial call to init_random_2K_seed(int16 random_seed) loads global ran_int16 with seed value
//  that starts the sequence.  Sequence length is 2048 bytes.
//  This is a Linear Congruential Pseudo-Random number generator that updates ran_int16 on each call.
//
//  Public routine dump_random8_2K(random_seed) dumps 2K sequence of random int8 values
//  as generated by random(8).  Init sequence with random_seed, which must be < 0x0800.
//
//  Public routine b=random8_32K() returns a randomized int8 (byte) that is taken from
//  a randomized portion of the 32-bit global word ran_int32.  Small and fast.
//  An initial call to init_random_32K_seed(int16 random_seed) loads global ran_int32 with seed value
//  that starts the sequence.  Sequence length is 32768 bytes.
//  This is a Linear Congruential Pseudo-Random number generator that updates ran_int32 on each call.
//  See random8_2K() for more LCG info.  This is an improvment over my earlier random8_2K() routine,
//  to get a longer sequence for memory testing, but no proper "randomness" testing was done on either
//  routine other than looking at a dump (both of which looked decent).
//
//  Public routine dump_random8_32K(random_seed) dumps 32K sequence of random int8 values
//  as generated by random8_32K.  Init sequence with random_seed, which must be < 0x8000.
//
//  Public routine b=random16_32K() returns a randomized int16 (word) that is taken from
//  a randomized portion of the 32-bit global word ran_int32.  Small and fast.
//  An initial call to init_random_32K_seed(int16 random_seed) loads global ran_int32 with seed value
//  that starts the sequence.  Sequence length is (maybe) 32768 bytes.
//  This is (kind-of) a Linear Congruential Pseudo-Random number generator that updates ran_int32 on each call.
//  See random8_2K() for more LCG info.
//  This algorithm taken from CCS picc compiler 3.249 and is similar to a Linear Congruential Generator,
//  but parameters don't follow the rules, and modulus done is after shifting.
//  Sequence length seemed longer than 32K, but not extensively checked.
//
//  Public routine dump_random16_32K(random_seed) dumps 32K sequence of random int16 values
//  as generated by random16_32K.  Init sequence with random_seed, which must be < 0x8000.
//
//  Public routine limit_min_max(param, min, max) limits param to be between min and max
//
//  Public routine b=bcd_to_bin_byte(bcd_byte) converts byte from bcd to binary
//
//============================================================================================
//
//      to do:
//          -
//
//
//      vaux_std.c            ver 8.0.0.0   (7/21/08)
//          - added limit_min_max(param, min, max) (was limit_max(param, max) in file mx_subs.c)
//          - expanded random number stuff
//
//      vaux_std.c            ver 7.1.0.0   (10/27/05)
//          - (updating version numbers to align with this master version)
//
//      vaux_std.c            ver 1.2   (3/7/05)
//          - replaced byte (was typedef) with int8
//          - replaced word (was typedef) with int16
//
//      vaux_std.c            ver 1.0   (8/1/02)
//          - new
//
//============================================================================================


//  ----- prototypes:
void init_random_2K_seed(int16 random_seed);          // init seed for the 2K-sequence random numbers
void init_random_32K_seed(int16 random_seed);         // init seed for the 32K-sequence random numbers

int8 random8_2K(void);                                // returns a random int8 (byte) from 2K-sequence
void dump_random8_2K(int16 random_seed);              // dumps 2K-sequence of random int8 values

int8 random8_32K(void);                               // returns a random int8 (word) from 32K-sequence
void dump_random8_32K(int16 random_seed);             // dumps 32K sequence of random int8 values

int16 random16_32K(void);                             // returns a random int16 (word) from 2K-sequence
void dump_random16_32K(int16 random_seed);            // dumps 32K-sequence of random int16 values

int8 limit_min_max(int8 param, int8 min, int8 max);   // limits param to be between min and max
int8 bcd_to_bin_byte(int8 bcd_byte);                  // convert byte from bcd to binary


// ----- globals:
int16 ran_int16=0x0001;                               // init with an seed (< 0x0800)
int32 ran_int32=0x00000001;                           // init with an seed (< 0x8000)



//--------------------------------------------------------------------------------------------
//  void init_random_2K_seed(int16 random_seed)     init seed for the 2K-sequence random numbers
//
//  Public routine init_random_2K_seed(random_seed) inits seed for the 2K-length sequence random
//  numbers by limiting seed and loading the 16-bit global ran_int16.  The seed must be < 0x0800.
//  This seed value starts the sequence.

void init_random_2K_seed(int16 random_seed)
{
  if (random_seed < 0x0800)
    ran_int16 = random_seed;                          // init sequence with seed
  else
    ran_int16 = 0x07FF;                               // init sequence with max seed
}


//--------------------------------------------------------------------------------------------
//  void init_random_32K_seed(int16 random_seed)    init seed for the 32K-sequence random numbers
//
//  Public routine init_random_32K_seed(random_seed) inits seed for the 32K-length sequence random
//  numbers by limiting seed and loading the 32-bit global ran_int32.  The seed must be < 0x8000.
//  This seed value starts the sequence.

void init_random_32K_seed(int16 random_seed)
{
  if (random_seed < 0x8000)
    ran_int32 = (int32)(random_seed);                 // init sequence with seed
  else
    ran_int32 = 0x00007FFF;                           // init sequence with max seed
}


//--------------------------------------------------------------------------------------------
//  int8 random8_2K(void)                           returns a random int8 (byte) from 2K-sequence
//
//  Public routine b=random8_2K() returns a randomized int8 (byte) that is taken from
//  a randomized portion of the 16-bit global word ran_int16.  Small and fast.
//  An initial call to init_random_2K_seed(int16 random_seed) loads global ran_int16 with seed value
//  that starts the sequence.  Sequence length is 2048 bytes.
//  This is a Linear Congruential Pseudo-Random number generator that updates ran_int16 on each call.
//
//  This is my original random number routine from 2002.
//
//  ran_int16 = (A * ran_int16 + C) % M
//
//  where:
//          0 <= A < M        (A is multiplier, M is modulus)
//          0 <= C < M        (C is constant)
//          0 <= seed < M     (seed is arbitrary, but changes sequence start point)
//
//  The sequence should repeat after M iterations.  Some rules must be met:
//    - calculations cannot overflow:  A*(M-1)+C < MAXINT  (MAXINT = 65535 for 16-bit)
//    - A-1 must be a multiple of every prime factor of M
//    - A-1 cannot be a multiple of M
//    - A-1 and M must be divisible by 4
//    - C must be prime (?)
//  Then the output is a scrambled sequenced of integers (0 to M-1) with a sequence length M.
//
//  So, choosing M = 2048 will give sequence length of 2048, and the lower 11-bits of are
//  ran_int16 are valid for the random number.
//
//          M = 2048  (divisible by 4;  primes = 2)
//          A = 21    (A < M;  20 is multiple of 2, and divisible by 4;  20 not multiple of 2048)
//          C = 1     (C < M;  prime)
//
//  We want to return only 8-bits -- the upper bits seemed more random, so we shift down.
//
//  Knuth's book should have the theory.  Some recommend combining two or more of
//  these (eg: xor) for more randomness.
//
//  Not tested for distribution or sequence, but it looks decent on a dump.
//  If ran_int16 is initiallized (seeded) to 0x0001, the sequence starts on the first
//  line below (02, 39, BF...).  Init ran_int16 to 0x0431 and you start at the second
//  line (00, 0F, 4D)...
//
//   ran_int16:
//     0001:     02, 39, BF, B5, E6, E3, A7, B3, B1, 94, 36, 78, E5, CE, EE, 86,
//     0431:     00, 0F, 4D, 5B, 84, D9, D5, 79, EF, AA, 04, 5E, C3, 04, 5C, 8C,
//     0461:     7E, 65, 5B, 81, A2, 4F, 83, BF, AD, 40, 52, C4, 21, BA, 4A, 12,
//     0091:     7C, 3B, E9, 27, 40, 45, B1, 85, EB, 56, 20, AA, FF, F0, B8, 18,
//     00C1:     FA, 91, F7, 4D, 5E, BB, 5F, CB, A9, EC, 6E, 10, 5D, A6, A6, 9E,
//     04F1:     F8, 67, 85, F3, FC, B1, 8D, 91, E7, 02, 3C, F6, 3B, DC, 14, A4,
//     0521:     76, BD, 93, 19, 1A, 27, 3B, D7, A5, 98, 8A, 5C, 99, 92, 02, 2A,
//     0151:     74, 93, 21, BF, B8, 1D, 69, 9D, E3, AE, 58, 42, 77, C8, 70, 30,
//     0181:     F2, E9, 2F, E5, D6, 93, 17, E3, A1, 44, A6, A8, D5, 7E, 5E, B6,
//     05B1:     F0, BF, BD, 8B, 74, 89, 45, A9, DF, 5A, 74, 8E, B3, B4, CC, BC,
//  ...
//     0681:     12, 89, 4F, 85, F6, 33, 37, 83, C1, E4, C6, 48, F5, 1E, 7E, 56,
//     02B1:     10, 5F, DD, 2B, 94, 29, 65, 49, FF, FA, 94, 2E, D3, 54, EC, 5C,
//     02E1:     8E, B5, EB, 51, B2, 9F, 13, 8F, BD, 90, E2, 94, 31, 0A, DA, E2,
//     0711:     8C, 8B, 79, F7, 50, 95, 41, 55, FB, A6, B0, 7A, 0F, 40, 48, E8,
//     0741:     0A, E1, 87, 1D, 6E, 0B, EF, 9B, B9, 3C, FE, E0, 6D, F6, 36, 6E,
//     0371:     08, B7, 15, C3, 0C, 01, 1D, 61, F7, 52, CC, C6, 4B, 2C, A4, 74,
//     03A1:     86, 0D, 23, E9, 2A, 77, CB, A7, B5, E8, 1A, 2C, A9, E2, 92, FA,
//     07D1:     84, E3, B1, 8F, C8, 6D, F9, 6D, F3, FE, E8, 12, 87, 18, 00, 00,
// (now it repeats)
//     0001:     02, 39, BF, B5, E6, E3, A7, B3, B1, 94, 36, 78, E5, CE, EE, 86,

int8 random8_2K(void)
{
  ran_int16 = (21 * ran_int16 + 1) % 2048;
  return ((int8)(ran_int16 >> 3));
}


//--------------------------------------------------------------------------------------------
//  void dump_random8_2K(int16 random_seed)         dumps 2K sequence of random int8 values
//
//  Public routine dump_random8_2K(random_seed) dumps 2K sequence of random int8 values
//  as generated by random(8).  Init sequence with random_seed, which must be < 0x0800.

void dump_random8_2K(int16 random_seed)
{
  int8  b;
  int16 l;

  init_random_2K_seed(random_seed);

  printf(send_sci_tx_byte, "\r\n\r\nDump of random8_2K values (2K sequence), using random_seed = %LX\r\n", random_seed);

  for (l=0; l<128; l++)                               // eg: 128 lines = 2048 total bytes
  {
    delay_ms(100);
    for (b=0; b<=15; b++)                             // 16 bytes/line
    {
      if (b == 0)
        printf(send_sci_tx_byte, "\r\n");

      printf(send_sci_tx_byte, " %X", random8_2K() );
    }
  }
  printf(send_sci_tx_byte, "\r\n");
}


//--------------------------------------------------------------------------------------------
//  int8 random8_32K(void)                          returns a random int8 (word) from 32K-sequence
//
//  Public routine b=random8_32K() returns a randomized int8 (byte) that is taken from
//  a randomized portion of the 32-bit global word ran_int32.  Small and fast.
//  An initial call to init_random_32K_seed(int16 random_seed) loads global ran_int32 with seed value
//  that starts the sequence.  Sequence length is 32768 bytes.
//  This is a Linear Congruential Pseudo-Random number generator that updates ran_int32 on each call.
//  See random8_2K() for more LCG info.  This is an improvment over my earlier random8_2K() routine,
//  to get a longer sequence for memory testing, but no proper "randomness" testing was done on either
//  routine other than looking at a dump (both of which looked decent).
//
//  This is a new routine in 2008.
//
//  Dump of random8_32K values (32K sequence), using random_seed = 0001
//
//   FA B2 28 5C 4E FE 6C 98 82 2A 90 B5 97 37 95 B1
//   8B 23 79 8D 5F EF 3D 4A 14 9C E2 E6 A8 28 66 62
//   1C 94 CB BF 71 E1 0F FB A5 0D 33 17 B9 19 38 14
//   AE 06 1C F0 82 D2 E0 AC 36 7E 85 49 CB 0B 09 C5
//   3F 77 6D 21 93 C4 B2 5E C8 F0 D6 7A DC FC DA 76
//   D0 E9 BF 53 A5 B5 83 0F 59 61 27 AB EE EE AC 28
//   62 5A 10 84 B6 A6 54 C0 EB D3 79 DD FF DF 7D D9
//   F3 CB 61 B5 C8 98 26 72 7C 44 CA 0E 10 D0 4E 8B
//   85 3D B3 E7 D9 89 F7 23 0D B5 1B 40 22 C2 20 3C
//   16 AE 04 18 EA 7A C8 D5 9F 27 6D 71 33 B3 F1 ED
//   (etc)

int8 random8_32K(void)
{
  ran_int32 = (32001 * ran_int32 + 11) % 32768;
  return (int8)(ran_int32 >> 7);
}


//--------------------------------------------------------------------------------------------
//  void dump_random8_32K(int16 random_seed)        dumps 32K sequence of random int8 values
//
//  Public routine dump_random8_32K(random_seed) dumps 32K sequence of random int8 values
//  as generated by random8_32K.  Init sequence with random_seed, which must be < 0x8000.

void dump_random8_32K(int16 random_seed)
{
  int8  b;
  int16 l;

  init_random_32K_seed(random_seed);

  printf(send_sci_tx_byte, "\r\n\r\nDump of random8_32K values (32K sequence), using random_seed = %LX\r\n", random_seed);

  for (l=0; l<2048; l++)                              // eg: 2048 lines = 32768 total words
  {
    delay_ms(100);
    for (b=0; b<=15; b++)                             // 16 words/line
    {
      if (b == 0)
        printf(send_sci_tx_byte, "\r\n");

      printf(send_sci_tx_byte, " %X", random8_32K() );
    }
  }
  printf(send_sci_tx_byte, "\r\n");
}


//--------------------------------------------------------------------------------------------
//  int16 random16_32K(void)                        returns a random int16 (word) from 32K-sequence
//
//  Public routine b=random16_32K() returns a randomized int16 (word) that is taken from
//  a randomized portion of the 32-bit global word ran_int32.  Small and fast.
//  An initial call to init_random_32K_seed(int16 random_seed) loads global ran_int32 with seed value
//  that starts the sequence.  Sequence length is (maybe) 32768 bytes.
//  This is (kind-of) a Linear Congruential Pseudo-Random number generator that updates ran_int32 on each call.
//  See random8_2K() for more LCG info.
//  This algorithm taken from CCS picc compiler 3.249 and is similar to a Linear Congruential Generator,
//  but parameters don't follow the rules, and modulus done is after shifting.
//  Sequence length seemed longer than 32K, but not extensively checked.
//
//  Dump of random16_32K values (32K sequence), using random_seed = 0001
//
//   41C6 167F 2781 446C 794C 15FC 59E3 1CFC 3F55 0FF6 0ABD 31DF 237C 2F1D 7DE1 4488
//   6202 52C0 6232 63DF 6957 1373 500F 2847 2C67 7566 4287 335A 4DAA 6489 773D 6F5A
//   6EEB 5656 6114 4A7C 31D2 2D86 19A2 69D8 353D 3B54 7D55 102F 1B37 7AAE 5E66 345C
//   63DB 6102 7A79 0399 28CC 60E4 1F1B 4B76 058F 7A60 28D9 079A 388F 751F 493F 0F37
//   48EE 2043 3F79 1E4D 3D0D 33FA 6FBF 36A6 2DDB 30E4 0586 148E 42DD 5929 0C6D 334F
//   62FF 1F57 2BE2 1D70 2621 26FC 7190 04B2 5359 3305 5690 5DC6 780A 1DDC 6B54 7BCD
//   63AB 373C 5648 679A 1452 23D3 1152 6E9E 6007 1A9F 11EA 25B6 66C3 1C06 4814 5B99
//   194A 7EB3 2001 371E 60AC 6E32 7289 7D32 329D 3753 1046 3A95 1E71 7E37 5390 4D58
//   1EF6 3A3A 651E 0A17 3CFA 1388 1F75 78F5 4E99 7E7C 3D17 665D 5F41 30BC 3D6E 4372
//   0C8F 4C10 2C70 125A 63C8 5B01 391C 5A30 0C33 7B3D 4692 5EC1 4A1D 51A5 640E 180D
//   (etc)

int16 random16_32K(void)
{
  ran_int32 = ran_int32 * 1103515245 + 12345;
  return ((int16)(ran_int32 >> 16) % 32767);
}


//--------------------------------------------------------------------------------------------
//  void dump_random16_32K(int16 random_seed)       dumps 32K sequence of random int16 values
//
//  Public routine dump_random16_32K(random_seed) dumps 32K sequence of random int16 values
//  as generated by random16_32K.  Init sequence with random_seed, which must be < 0x8000.

void dump_random16_32K(int16 random_seed)
{
  int8  b;
  int16 l;

  init_random_32K_seed(random_seed);

  printf(send_sci_tx_byte, "\r\n\r\nDump of random16_32K values (32K sequence), using random_seed = %LX\r\n", random_seed);

  for (l=0; l<2048; l++)                              // eg: 2048 lines = 32768 total words
  {
    delay_ms(100);
    for (b=0; b<=15; b++)                             // 16 words/line
    {
      if (b == 0)
        printf(send_sci_tx_byte, "\r\n");

      printf(send_sci_tx_byte, " %LX", random16_32K() );
    }
  }
  printf(send_sci_tx_byte, "\r\n");
}


//--------------------------------------------------------------------------------------------
//  int8 limit_min_max(int8 param, int8 min, int8 max)  limits param to be no higher than max
//
//  Public routine limit_min_max(param, min, max) limits param to be between min and max

int8 limit_min_max(int8 param, int8 min, int8 max)
{
  if (param > max)
    return (max);
  else if (param < min)
    return (min);
  else
    return (param);
}


//--------------------------------------------------------------------------------------------
//  int8 bcd_to_bin_byte(int8 bcd_byte)             convert byte from bcd to binary
//
//  Public routine b=bcd_to_bin_byte(bcd_byte) converts byte from bcd to binary

int8 bcd_to_bin_byte(int8 bcd_byte)
{
  return( ((bcd_byte >> 4) * 10) + (bcd_byte & 0x0F) );
}


