将 C 转换为 Python

Converting C into Python

我正在尝试转换解析 Linux 库 rtl_fm 输出的 C 模块。它用于通过 DVB-T 加密狗从 Efergy 仪表捕获能源使用情况

C 模块工作正常,但我希望它用 python 编写,以便与我拥有的其他 python 模块交互

我把常量放在了constant.py

我完全无法转换行:cursamp = (int16_t) (fgetc(stdin) | fgetc(stdin)<<8); 我尝试以多种不同的方式进行转换。每次尝试都以错误结束!

好像是两类问题:1.输入结果的类型转换 2.如何将fgetc()转换成python.

我也无法将 while(!feof(stdin)) 转换为 python

有人可以帮忙吗?

C 代码如下:

#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.
    }
}

和 Python 转换(没有文件记录的情况下稍微简化):

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()

C 的 fgetc(stdin) 转换为 Python 2 的 ord(sys.stdin.read(1)[0]) -- 从 stdin 的下一个字节返回一个数值。 (在 Python 3 中,您必须将 sys.stdin 重新打开为二进制文件才能实现此目的,否则 .read(1) 将获得 Unicode 字符,而不是字节)。

|<< 运算符在 Python 中的工作方式与 C 中的相同,因此,没问题。

在 EOF,sys.stdin.read(1) returns 一个空列表(因此 [0] 会失败,但您可以通过 "decomposing" 上面的表达式来检查)。例如:

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)

关于字节顺序(字节顺序)和字符符号(C 和 Python 的常见问题)的挑剔问题。