/*+============================================================================
|
| LEGAL
|
|     PN Version 1.0 - A Program for generating pseudonoise sequences.
|     Copyright (C) 1986-2017 by Sean Erik O'Connor.  All Rights Reserved.
|
|     This program is free software: you can redistribute it and/or modify
|     it under the terms of the GNU General Public License as published by
|     the Free Software Foundation, either version 3 of the License, or
|     (at your option) any later version.
|
|     This program is distributed in the hope that it will be useful,
|     but WITHOUT ANY WARRANTY; without even the implied warranty of
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
|     GNU General Public License for more details.
|
|     You should have received a copy of the GNU General Public License
|     along with this program.  If not, see <http://www.gnu.org/licenses/>.
|     
|     The author's address is artificer!AT!seanerikoconnor!DOT!freeservers!DOT!com
|     with !DOT! replaced by . and the !AT! replaced by @
|
+============================================================================*/

#include <stdio.h>

char * legalNotice =
{
    "\n"
    "PN Version 1.0 - A Program for generating pseudonoise sequences.\n"
    "Copyright (C) 1986-2017 by Sean Erik O'Connor.  All Rights Reserved.\n"
    "\n"
    "PN comes with ABSOLUTELY NO WARRANTY; for details see the\n"
    "GNU General Public License.  This is free software, and you are welcome\n"
    "to redistribute it under certain conditions; see the GNU General Public License\n"
    "for details.\n\n"
}  ;

int pn( void ) ;

/* Print out values of a sample binary PN sequence. */

int main( int argc, char * argv[] )
{
    int i ;

    /*  Show the legal notice first.  */
    printf(  "%s", legalNotice )  ;

    /* Print out PN sequence values. */
    for (i = 1 ;  i <= 15 ;  ++i)
    {
        printf( "pn %3d = %3d\n", i, pn() ) ;
    }

    return 0 ;
}


/* Compute the bits of a binary PN sequence. */

int pn( void )
{
    static unsigned int shiftRegister = 1 ;   /* Initial state of shift register, */
                                              /* a  = 1, a  = ... = a  = 0        */
                                              /*  0       1          3            */

    unsigned int m        = 4 ;               /* Period of PN sequence = 2^m - 1 = 15   */

    unsigned int primPoly = 0x13 ;            /* Primitive polynomial coefficients,     */
                                              /* x^4 + x + 1 = 10011 (binary) = 13 hex  */

    unsigned int mask     = (1 << (m-1)) ;    /* Selects the mth bit.                   */

    unsigned int multiplier =
                 (primPoly ^ (1 << m)) ;      /* Feedback multiplier, corresponding to   */
                                              /* the taps f ... f on the shift register, */
                                              /*           3     0                       */
                                              /* equal to the primitive polynomial       */
                                              /* coefficients with highest degree term   */
                                              /* omitted.                                */

    unsigned int feedback ; /* Feedback bit.                  */
    unsigned int bit ;      /* Bit 0 or 1 of the PN sequence. */
    unsigned int product ;  /* Bitwise product.               */
    unsigned int i ;

    product = shiftRegister & multiplier ;   /* Modulo 2 multiplication of feedback */
                                             /* taps times shift register contents  */
                                             /* in parallel.                        */

    /* Sum up the product bits modulo 2 to get the feedback bit. */
    for (i = 1, feedback = 0 ;  i <= m ;  ++i)
    {
        feedback ^= (1 & product) ;         /* Add first bit of the product into  */
                                            /* the running sum of the feedback.   */

        product >>= 1 ;                     /* Shift to expose next bit of the product. */
    }

    bit = shiftRegister & 1 ;               /* Save the zeroth (PN sequence) bit of */
                                            /* of the shift register.               */

    shiftRegister >>= 1 ;                   /* Shift the shift register contents.   */

    if (feedback)                           /* Add feedback (if any) to the shift register */
    {                                       /* contents.                                   */
        shiftRegister ^= mask ;
    }

    return( bit ) ;                         /* Return the PN sequence bit. */
}