Converting C into Python
Question: I am trying to convert a C module that parses the output from the Linux
library rtl_fm. It is used for catching energy usage from an Efergy meter
throuh a DVB-T dongle

The C module works fine but I want it written in python to interact with other
python modules i have

I have put the constants in constant.py

I am totally stuck in converting the row: **cursamp = (int16_t) (fgetc(stdin) | fgetc(stdin) <<8);** that I have tried to convert in a lot of different ways. Every try ends with an error!

It seems to be two types of problems: 1. Type conversion of the input result
2. How to convert fgetc() into python.

I also have troubles converting **while(!feof(stdin))** into python

Anyone that could help?

C code below:

    
    
    #include <stdio.h>
    #include <stdint.h>
    #include <time.h>
    #include <math.h>
    
    #include <stdlib.h> // For exit function
    
    #define VOLTAGE         240 /* Refernce Voltage */
    #define CENTERSAMP      100 /* Number of samples needed to compute for the wave center */
    #define PREAMBLE_COUNT      40  /* Number of high(1) samples for a valid preamble */
    #define MINLOWBIT       3   /* Number of high(1) samples for a logic 0 */
    #define MINHIGHBIT      8   /* Number of high(1) samples for a logic 1 */
    #define E2BYTECOUNT     8   /* Efergy E2 Message Byte Count */
    #define FRAMEBITCOUNT       64  /* Number of bits for the entire frame (not including preamble) */
    
    
    #define LOGTYPE        1 // Allows changing line-endings - 0 is for Unix /n, 1 for Windows /r/n
    #define SAMPLES_TO_FLUSH  10 // Number of samples taken before writing to file.
                     // Setting this too low will cause excessive wear to flash due to updates to
                     // filesystem! You have been warned! Set to 10 samples for 6 seconds = every min.
    
    int loggingok;   // Global var indicating logging on or off
    int samplecount; // Global var counter for samples taken since last flush
    FILE *fp;    // Global var file handle
    
    int calculate_watts(char bytes[])
    {
    
    char tbyte;
    double current_adc;
    double result;
    int i;
    
    time_t ltime; 
    struct tm *curtime;
    char buffer[80];
    
        /* add all captured bytes and mask lower 8 bits */
    
        tbyte = 0;
    
        for(i=0;i<7;i++)
            tbyte += bytes[i];
    
        tbyte &= 0xff;
    
        /* if checksum matches get watt data */
    
        if (tbyte == bytes[7])
        {
            time( &ltime );
            curtime = localtime( &ltime );
            strftime(buffer,80,"%x,%X", curtime);
    
            current_adc = (bytes[4] * 256) + bytes[5];
            result  = (VOLTAGE * current_adc) / ((double) 32768 / (double) pow(2,bytes[6]));
            printf("%s,%f\n",buffer,result);
            if(loggingok) {
              if(LOGTYPE) {
                fprintf(fp,"%s,%f\r\n",buffer,result);
              } else {
                fprintf(fp,"%s,%f\n",buffer,result);
              }
              samplecount++;
              if(samplecount==SAMPLES_TO_FLUSH) {
                samplecount=0;
                fflush(fp);
              }
            }
            fflush(stdout);
            return 1;
        }
        //printf("Checksum Error \n");
        return 0;
    }
    
    void  main (int argc, char**argv) 
    {
    
    char bytearray[9];
    char bytedata;
    
    int prvsamp;
    int hctr;
    int cursamp;
    int bitpos;
    int bytecount;
    
    int i;
    int preamble;
    int frame;
    int dcenter;
    int dbit;
    
    long center;
    
        if(argc==2) {
          fp = fopen(argv[1], "a"); // Log file opened in append mode to avoid destroying data
          samplecount=0; // Reset sample counter
          loggingok=1;
          if (fp == NULL) {
              perror("Failed to open log file!"); // Exit if file open fails
              exit(EXIT_FAILURE);
          }
        } else {
          loggingok=0;
        }
    
        printf("Efergy E2 Classic decode \n\n");
    
    
        /* initialize variables */
    
        cursamp = 0;
        prvsamp = 0;
    
        bytedata = 0;
        bytecount = 0;
        hctr = 0;
        bitpos = 0;
        dbit = 0;
        preamble = 0;
        frame = 0;
    
        dcenter = CENTERSAMP;
        center = 0;
    
        while( !feof(stdin) ) 
        {
    
            cursamp  = (int16_t) (fgetc(stdin) | fgetc(stdin)<<8);
    
            /* initially capture CENTERSAMP samples for wave center computation */
    
            if (dcenter > 0)
            {
                dcenter--;
                center = center + cursamp;  /* Accumulate FSK wave data */ 
    
                if (dcenter == 0)
                {
                    /* compute for wave center and re-initialize frame variables */
    
                    center = (long) (center/CENTERSAMP);
    
                    hctr  = 0;
                    bytedata = 0;
                    bytecount = 0;
                    bitpos = 0;
                    dbit = 0;
                    preamble = 0;
                    frame = 0;
                }
    
            }
            else
            {
                if ((cursamp > center) && (prvsamp < center))       /* Detect for positive edge of frame data */
                    hctr = 0;
                else 
                    if ((cursamp > center) && (prvsamp > center))       /* count samples at high logic */
                    {
                        hctr++;
                        if (hctr > PREAMBLE_COUNT)  
                            preamble = 1;
                    }
                    else 
                        if (( cursamp < center) && (prvsamp > center))
                        {
                            /* at negative edge */
    
                            if ((hctr > MINLOWBIT) && (frame == 1))
                            {
                                dbit++;
                                bitpos++;   
                                bytedata = bytedata << 1;
                                if (hctr > MINHIGHBIT)
                                    bytedata = bytedata | 0x1;
    
                                if (bitpos > 7)
                                {
                                    bytearray[bytecount] = bytedata;
                                    bytedata = 0;
                                    bitpos = 0;
    
                                    bytecount++;
    
                                    if (bytecount == E2BYTECOUNT)
                                    {
    
                                        /* at this point check for checksum and calculate watt data */
                                        /* if there is a checksum mismatch compute for a new wave center */
    
                                        if (calculate_watts(bytearray) == 0)
                                            dcenter = CENTERSAMP;   /* make dcenter non-zero to trigger center resampling */
                                    }
                                }
    
                                if (dbit > FRAMEBITCOUNT)
                                {   
                                    /* reset frame variables */
    
                                    bitpos = 0;
                                    bytecount = 0;
                                    dbit = 0;
                                    frame = 0;
                                    preamble = 0;
                                    bytedata = 0;
                                }
                            }
    
                            hctr = 0;
    
                        } 
                        else
                            hctr = 0;
    
                if ((hctr == 0) && (preamble == 1))
                {
                    /* end of preamble, start of frame data */
                    preamble = 0;
                    frame = 1;
                }
    
            } /* dcenter */
    
            prvsamp = cursamp;
    
        } /* while */
        if(loggingok) {
            fclose(fp); // If rtl-fm gives EOF and program terminates, close file gracefully.
        }
    }
    

And the Python conversion (a little simplified without file logging):

    
    
    from datetime import date
    from datetime import time
    from datetime import datetime
    import cmath
    import constant
    import sys
    import logging
    
    logging.basicConfig(level=logging.DEBUG)
    logger = logging.getLogger(__name__)
    
    
    class _Getch:
        """Gets a single character from standard input.  Does not echo to the
    screen."""
        def __init__(self):
            try:
                self.impl = _GetchWindows()
            except ImportError:
                self.impl = _GetchUnix()
    
        def __call__(self): return self.impl()
    
    
    class _GetchUnix:
        def __init__(self):
            import tty, sys
    
        def __call__(self):
            import sys, tty, termios
            fd = sys.stdin.fileno()
            old_settings = termios.tcgetattr(fd)
            try:
                tty.setraw(sys.stdin.fileno())
                ch = sys.stdin.read(1)
            finally:
                termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
            return ch
    
    
    class _GetchWindows:
        def __init__(self):
            import msvcrt
    
        def __call__(self):
            import msvcrt
            return msvcrt.getch()
    
    
    getch = _Getch()
    
    def calculate_watts(*args):
        logger.info('Start Calculation')
        now = datetime.now()
    
        tbyte = 0
    
        for i in range(0,7):
            tbyte += bytes[i]
    
        tbyte = tbyte & 0xff
    
        if (tbyte == bytes[7]):
            current_adc = (bytes[4] * 256) + bytes[5]
            result = (constant.VOLTAGE * current_adc) / (32768 / pow(2,bytes[6]))
            print "%s,%f\n" % (now,result)
            exit(0)
        else:
            print "Checksum Error \n"
            exit(1)
    
    def  main(*argv):
        logger.info('Starting Main')
    
        print "Efergy E2 Python decode \n\n"
    
        cursamp = 0
        prvsamp = 0
    
        bytedata = 0
        bytecount = 0
        hctr = 0
        bitpos = 0
        dbit = 0
        preamble = 0
        frame = 0
    
        dcenter = constant.CENTERSAMP
        center = 0
    
        while (1):
    
            cursamp  = (int)((int)(_Getch()) | (int)(_Getch())<<8)
            logger.debug('cursamp: %f',cursamp)
    
            if (dcenter > 0):
                dcenter -= 1
                center = center + cursamp    #/* Accumulate FSK wave data */ 
                if (dcenter == 0):
    
                    center = (center/constant.CENTERSAMP)
                    hctr  = 0
                    bytedata = 0
                    bytecount = 0
                    bitpos = 0
                    dbit = 0
                    preamble = 0
                    frame = 0
            else:
                if ((cursamp > center) and (prvsamp < center)):        #/* Detect for positive edge of frame data */
                    hctr = 0
                else: 
                    if ((cursamp > center) and (prvsamp > center)):        #/* count samples at high logic */
                        hctr += 1
                        if (hctr > constant.PREAMBLE_COUNT):    
                            preamble = 1
                    else: 
                        if (( cursamp < center) and (prvsamp > center)):
                            #/* at negative edge */
                            if ((hctr > constant.MINLOWBIT) and (frame == 1)):
                                dbit += 1
                                bitpos += 1    
                                bytedata = bytedata << 1
                                if (hctr > constant.MINHIGHBIT):
                                    bytedata = bytedata | 0x1
                                if (bitpos > 7):
                                    bytearray[bytecount] = bytedata
                                    bytedata = 0
                                    bitpos = 0
    
                                    bytecount += 1
    
                                    if (bytecount == constant.E2BYTECOUNT):
    
                                        # /* at this point check for checksum and calculate watt data */
                                        #  /* if there is a checksum mismatch compute for a new wave center */
    
                                        if (calculate_watts(bytearray) == 0):
                                            dcenter = constant.CENTERSAMP   #/* make dcenter non-zero to trigger center resampling */
    
                                if (dbit > constant.FRAMEBITCOUNT):
                                    #/* reset frame variables */
    
                                    bitpos = 0
                                    bytecount = 0
                                    dbit = 0
                                    frame = 0
                                    preamble = 0
                                    bytedata = 0
    
                            hctr = 0
    
                        else:
                            hctr = 0
    
                if ((hctr == 0) and (preamble == 1)):
    
                    #/* end of preamble, start of frame data */
                    preamble = 0
                    frame = 1
    
             #/* dcenter */
    
            prvsamp = cursamp
    
    if __name__ == "__main__":
      main()
    


Answer: C's `fgetc(stdin)` translates to Python 2's `ord(sys.stdin.read(1)[0])` \--
returning a numeric value from the next byte of `stdin`. (In Python 3, you'll
have to reopen `sys.stdin` as binary to achieve that, otherwise `.read(1)`
will get a Unicode character, not a byte).

The `|` and `<<` operators work the same in Python as in C, so, no problem
there.

At EOF, `sys.stdin.read(1)` returns an empty list (so the `[0]` would fail,
but you can check for that by "decomposing" the above expression). For
example:

    
    
    ateof = False
    
    def getabyte():
        data = sys.stdin.read(1)
        if data: return False, ord(data)
        else: return True, 0
    
    def getanint():
        global ateof
        ateof, byte1 = getabyte()
        if not ateof:
            ateof, byte2 = getabyte()
        if ateof: return True, 0
        else: return False, byte1 | (byte2<<8)
    

net of finicky issues wrt endianness (byte order) and character's signedness
(issues common to C and Python).

