I have the following python code… and want to write this Code in… Python-C-API
from enum import Enum
class MqWaitOnEventE(Enum):
NO = 0
ONCE = 1
FOREVER = 2
Thanks for help.
FIRST approach
// enum definition
PyObject *enumModO=NULL, *enumDictO=NULL, *intEnumO=NULL;
LngErrorCheckN(enumModO = PyImport_ImportModule("enum"));
LngErrorCheckN(enumDictO = PyModule_GetDict(enumModO));
LngErrorCheckN(intEnumO = PyDict_GetItemString(enumDictO,"IntEnum"));
// get 'MqWaitOnEventE '
PyObject *dictMqWaitOnEventE = NULL, *result=NULL, *base=NULL;
LngErrorCheckN(dictMqWaitOnEventE = PyDict_New());
LngErrorCheck(PyDict_SetItemString (dict, "__module__", PyUnicode_FromString("pymsgque")));
LngErrorCheck(PyDict_SetItemString (dict, "NO", OT_NEW_INT_OBJ(MQ_WAIT_NO)));
LngErrorCheck(PyDict_SetItemString (dict, "ONCE", OT_NEW_INT_OBJ(MQ_WAIT_ONCE)));
LngErrorCheck(PyDict_SetItemString (dict, "FOREVER", OT_NEW_INT_OBJ(MQ_WAIT_FOREVER)));
LngErrorCheckN(base = PyTuple_Pack(1, intEnumO));
LngErrorCheckN(result = PyObject_CallFunction((PyObject *)&PyType_Type, "sOO","MqWaitOnEventE", base, dictMqWaitOnEventE));
end with following error…
Traceback (most recent call last):
File "…/MyServer.py", line 14, in <module>
import pymsgque
File "…/python3.7/enum.py", line 151, in __new__
enum_members = {k: classdict[k] for k in classdict._member_names}
AttributeError: 'dict' object has no attribute '_member_names'
what is this? … does python require som internals from me ?
This is the type-safe solution for a enum in C-Module initialization file…
MqBuffer… is my string buffer class
NS(…) is a macro to create a unique namespace… I use this for all c-extern objects
.
the example will create the new MqSlaveE class in the module namespace.
PyObject* m = PyModule_Create(&ModuleDef);
...
MQ_BUF buf = MqBufferCreate(1000);
MqBufferAppendC(buf,"from enum import IntEnum\n");
MqBufferAppendC(buf,"class MqSlaveE(IntEnum):\n");
MqBufferAppendV(buf," LOOPBACK = %i\n", MQ_SLAVE_LOOPBACK);
MqBufferAppendV(buf," OTHER = %i\n", MQ_SLAVE_OTHER);
MqBufferAppendV(buf," FILTER = %i\n", MQ_SLAVE_FILTER);
MqBufferAppendV(buf," MASTER = %i\n", MQ_SLAVE_MASTER);
MqBufferAppendV(buf," USER = %i\n", MQ_SLAVE_USER);
PyObject *g, *dl, *dg, *v;
MQ_CST script = MqBufferGetC_e(buf);
g = PyImport_AddModule("__main__");
dg = PyModule_GetDict(g);
dl = PyModule_GetDict(m);
LngErrorCheckN(v = PyRun_String(script, Py_file_input, dg, dl));
Py_DECREF(v);
NS(MqSlaveE) = PyDict_GetItemString(dl,"MqSlaveE");
MqBufferDelete(&buf);
return m;
to check the object and extract the value I use a proc…
enum MqErrorE NS(Get_Enum_FromObj) (PyObject *enumT, PyObject *enumE, MQ_INT *ret) {
if (!PyObject_IsInstance(enumE, enumT)) {
PyErr_Format(PyExc_TypeError,
"input_enum_type = '%s' is not the required_enum_type = '%s'",
Py_TYPE(enumE)->tp_name, ((PyTypeObject*)enumT)->tp_name
);
return MQ_ERROR;
}
return PyObj_AsINT(enumE,ret);
}
Related
I'm trying to get a blob of a repository with libgit2:
#include <git2.h>
#include <stdio.h>
int main() {
git_libgit2_init();
git_repository *repo = NULL;
int error = git_repository_open(&repo, "/home/martin/Dokumente/TestRepository");
if (error < 0) {
const git_error *e = git_error_last();
printf("Error %d/%d: %s\n", error, e->klass, e->message);
exit(error);
}
git_diff *diff = NULL;
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
opts.flags |= GIT_DIFF_IGNORE_WHITESPACE;
opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED;
error = git_diff_index_to_workdir(&diff, repo, NULL, &opts);
if (error < 0) {
const git_error *e = git_error_last();
printf("Error %d/%d: %s\n", error, e->klass, e->message);
exit(error);
}
git_patch* patch = nullptr;
git_patch_from_diff(&patch, diff, 0);
bool oldFile = false;
const git_diff_delta *dd = git_patch_get_delta(patch);
const git_oid &id = (!oldFile) ? dd->new_file.id : dd->old_file.id;
git_object *obj = nullptr;
git_object_lookup(&obj, repo, &id, GIT_OBJECT_ANY);
git_blob* blob = reinterpret_cast<git_blob *>(obj);
const char* pointer = (const char*)git_blob_rawcontent(blob);
// cleanup
git_object_free(obj);
git_patch_free(patch);
git_diff_free(diff);
git_repository_free(repo);
return 0;
}
The repository
create a new repository
commit a file like:
1
2
3
4
remove the 4 again, but do not commit
let the program run
Expected:
The program runs fine.
Observed:
obj is still a nullptr after executing
git_object_lookup()
When setting the variable oldFile to true, the program runs fine and the pointer "pointer" contains the raw blob.
Does anybody know why I don't get a valid object from git_object_lookup() back?
The problem is that you're trying to get an object of id dd->new_file.id. This file is in the working directory, as it hasn't been added or committed yet. This means it isn't in the repository yet. When you run git_object_lookup(), it can't find the object as it hasn't been added to the tree. The OID doesn't correspond to any match so it returns null.
If you want to get the current working directory data, you must first create the object in the tree using git_blob_create_from_workdir, and then when trying to access it, it would be found. So your new code might look like:
bool oldFile = false;
const git_diff_delta *dd = git_patch_get_delta(patch);
git_oid id;
if (!oldFile) {
error = git_blob_create_from_workdir(&id, repo, dd->new_file.path);
if (error < 0) {
const git_error *e = git_error_last();
printf("Error %d/%d: %s\n", error, e->klass, e->message);
exit(error);
}
} else {
id = dd->old_file.id;
}
git_object *obj = nullptr;
git_object_lookup(&obj, repo, &id, GIT_OBJECT_ANY);
git_blob* blob = reinterpret_cast<git_blob *>(obj);
const char* pointer = (const char*)git_blob_rawcontent(blob);
When you diff between the index and the workdir, the new side of the delta represents the file in the working directory. Its id is the hash of the file on disk. Unless you explicitly insert that blob into the repository's object store by some other means, there's no reason for it to be there yet.
I have a C Struct:
struct FastSax {
int parseErrorType;
int parserStatus;
int cacheIndex;
char* input;
int (* findOpen)(FastSax *, int);
int (* findClose)(FastSax *, int);
void (* print)(char *);
char* (* parse)(FastSax* , const char*);
};
Initialized like this:
FastSax* getDefault() {
FastSax *sax = malloc(sizeof (FastSax));
sax->cacheIndex = -1;
sax->findOpen = &findOpen;
sax->findClose = &findClose;
sax->parse = & parse;
sax->hasMoreTokens = &hasMoreTokens;
sax->fetchNextToken = &fetchNextToken;
sax->print = &print;
sax->parseErrorType = PARSE_ERROR_NONE;
sax->parserStatus = PARSE_STATUS_INSUFFICIENT_DATA;
sax->input = malloc(50 * sizeof (char));
strncpy(sax->input, "", 10);
sax->input[strlen(sax->input)] = '\0';
return sax;
}
I am calling the parse function in a loop that processes lines from a file.
The parse function runs and based on its output, updates some properties of the struct object.
char* parse(FastSax* fs , const char *freshData) {
//parse operations on freshData
fs.cacheIndex = strlen(freshData);
fs.parserStatus = 4;
/**Parser code here**/
//not a constant string
return "the-result-of-the-parse";
}
In Swift, I do:
class ParserClient{
let fastSax = getDefault()
func parse(line: String) -> Int{
let ptr = fastSax
var status:Int32 = -1
let fs: FastSax = ptr!.withMemoryRebound(to: FastSax.self, capacity: 1) {
$0.pointee
}
let out = fs.parse(ptr , line)
//consume the first token
if fs.parseErrorType == PARSE_ERROR_NONE{
var token = String(cString: out)
self.delegate.endEntry(entry: token)
while true {
var _token = String(cString: fs.parse(ptr ,""))
Log.out("\(_token) , parser-status: \(fs.parserStatus)")
if fs.parserStatus == PARSE_STATUS_OK {
self.delegate.endEntry(entry: _token)
}else{
break
}
}
}else{
Log.out("Error: parser-status: \(fs.parserStatus) , error-type: \(fs.parseErrorType)")
}
return Int(fs.parserStatus)
}
}
When the parser code is invoked in C, it works fine.
But when called from Swift, I noticed that the struct object i.e. fs properties were not being updated on each iteration of the while loop.
Question:
How do I make sure that the struct's properties are updated when it calls C code.
Is the copy of the struct invoked from Swift different from the one being used by C?
Is the copy of the struct invoked from Swift different from the one being used by C?
Exactly. This
let fs: FastSax = ptr!.withMemoryRebound(to: FastSax.self, capacity: 1) {
$0.pointee
}
is a (complicated) way of making a copy of the struct pointed to by ptr. Then
let out = fs.parse(ptr , line)
updates the structure pointed to by ptr (which is the default structure obtained before) and not the structure pointed to by fs.
What you probably want is simply
let out = fastSax!.pointee.parse(fastSax, line)
assuming that fastSax is not nil. Use optional binding or optional chaining if that is not guaranteed. The ptr and fs variables are not needed.
I'm simply trying to add one message to another message (up to 60 times times)
My .proto file looks as follows;
syntax = "proto3";
message FeatureFile {
string fileName= 2;
string Id= 3;
repeated Feature features = 1;
}
message Feature {
int32 version = 1;
int32 epochTime = 2;
int32 noOfObs= 3;
int32 frequency = 4;
}
I have tried to make a callback function to add repeated data, but cannot make it work.
bool encode_string(pb_ostream_t* stream, const pb_field_t* field, void* const* arg)
{
const char* str = (const char*)(*arg);
if (!pb_encode_tag_for_field(stream, field))
return false;
return pb_encode_string(stream, (uint8_t*)str, strlen(str));
}
bool encode_repeatedMsg(pb_ostream_t* stream, const pb_field_t* field, void* const* arg)
{
const char* obj = (const char*)(*arg);
int i;
for (i = 0; i < 60; i++)
{
if (!pb_encode_tag_for_field(stream, field))
return false;
if (!pb_encode_submessage(stream, Feature_fields, *arg))
return false;
}
return true;
}
int main()
{
FeatureFile featurefile = FeatureFile_init_zero;
Feature feature = Feature_init_zero;
featurefile.fileName.arg = "092536.csv";
featurefile.fileName.funcs.encode = &encode_string;
featurefile.Id.arg = "";
featurefile.Id.funcs.encode = &encode_string;
feature.version = 1;
feature.epochTime = 12566232;
feature.noOfObs = 260;
feature.frequency = 200;
featurefile.features.funcs.encode = &encode_repeatedMsg;
I thought I could call the repeated encoding like the last line of code shows, but I doesn't allow me.
The callback itself is supposed to add 60 of the same messages (feature) to the the featurefile.
Can anyone help me here?
I myself have never used the callbacks in nanopb. I do have been using the .options file to statically allocate the desired array size. Your case this might be a bit much as your require 60 messages but this is how you do it:
You create a file with the same name as your .proto file but give it the extension .options. You place it in the same folder as your .proto file. In that file you mention there repeated variable name and assign it a size:
# XXXX.options
FeatureFile.features max_count:16
More information on the nanopb options can be found here.
Earlier I was fixing a lexer for my parser; now I have to create a validater for it. My idea was to convert the enumeration constants to strings by using the following preprocessor macro: #define MACRO_STRINGIFY(x) #x.
Then I made a function to compare various token values lactually, I made three, but they are all the same with a few minor changes):
unsigned int compare_keyword( enum script_keywords keyword, char *token ) {
char *temporary = MACRO_STRINGIFY( keyword );
unsigned int i = 0;
for (; i < (strlen( "KEYWORD_" ) + 1); i++) {
++temporary;
}
// 0 on match, 1 on no match
return strcmp( temporary, token ) ? 1 : 0;
}
Now, this function works absolutely fine... when keyword is the enumeration constant:
void test() {
printf( "\nIF is " );
// Finish the sentence based on the return value
compare_keyword( KEYWORD_IF, "IF" ) ? printf( "not a keyword.\n" ) : printf( "a keyword.\n" );
}
test(); //--> Outputs 'IF is a keyword' like expected.
On the other hand, the function does not work as intended if I pass a value like 1 (the value which the symbolic enumeration constant KEYWORD_IF resolves to.):
// Same as last time with one edit:
void test() {
/* See above code with following change on line 4 */
compare_keyword( 1, "IF" ) /* etc... */
/* Rest of code from previous test */
}
test(); //--> Outputs 'IF is not a keyword' even if KEYWORD_IF resolves to the value 1.
The point I'm getting across here is that the preproccessor is very literal, and I would much prefer using a for loop to loop through the constants efficiently without bloating the code size (which is what would happen if I end up using enumeration constants). Therefore, the question is how can I convert plain integer values to their symbolic names without using switch…case… or if…else…?
Edit: Enumeration Details:
enum script_keywords {
KEYWORD_IF = 1,
KEYWORD_THEN = 2,
KEYWORD_ELSEIF = 3,
KEYWORD_ELSE = 4,
KEYWORD_ENDIF = 5,
KEYWORD_FOR = 6,
KEYWORD_TO = 7,
KEYWORD_STEP = 8,
KEYWORD_EXITFOR = 9,
KEYWORD_NEXT = 10,
KEYWORD_LOOP = 11,
KEYWORD_WHILE = 12,
KEYWORD_EXITLOOP = 13,
KEYWORD_ENDLOOP = 14,
KEYWORD_DO = 15,
KEYWORD_EXITDO = 16,
KEYWORD_UNTIL = 17,
KEYWORD_ON = 18,
KEYWORD_GOTO = 19,
KEYWORD_CALL = 20,
KEYWORD_LET = 21,
KEYWORD_DIM = 22,
KEYWORD_AS = 23
};
The Macro "MACRO_STRINGIFY" is evaluated at compile time by the preprocessor. It will return the actual name of the argument, so
MACRO_STRINGIFY(keyword) -> "keyword"
MACRO_STRINGIFY(KEYWORD_IF) -> "KEYWORD_IF"
MACRO_STRINGIFY(1) -> "1"
Apparently this will not lead to any solution.
Instead one could use a compile-time generated key-value mapping to implement such functionality:
struct map
{
int key;
const char* value;
};
struct map mappings[] =
{
{ KEYWORD_IF, "IF" },
{ KEYWORD_ELSE, "ELSE" }
};
and then simply iterate those mapping entries at runtime to find out what you need:
static int is_keyword(const char* str)
{
int i;
const int count = sizeof(mappings) / sizeof(mappings[0]);
for(i = 0; i < count; i++)
{
struct map* m = &mappings[i];
if(strcmp(str, m->value) == 0)
{
return 1;
}
}
return 0;
}
void test()
{
const char* str = "IF";
const char* what;
if(is_keyword(str))
{
what = "a keyword";
}
else
{
what = "not a keyword";
}
printf("%s is %s.\n", str, what);
}
This is about as minimal as it may get. The executable binary does not normally include names of enumeration values as known from e.g. Java.
To extend this even further, you could do some preprocessor voodoo to generate the mapping array (semi-) automatically. But as I am not a big friend of preprocessor voodoo I will skip that ;)
I'm trying to get my Arduino to send data to a python script on my computer and for some reason the python script is reading the data incorrectly. Specifically, it reads the data correctly for about 4-5 receives then it starts to get out of sync. Below is my code:
Arduino:
struct sensorData
{
char beginPad[5];
int data0;
char pad0;
//int data1;
//char pad1;
//int data2;
};
union data
{
unsigned char buffer[sizeof(sensorData)];
sensorData vars;
};
data sendData;
void setup()
{
Serial.begin(9600);
static char temp[5] = {0, 1, 2, 3, 4};
memcpy(sendData.vars.beginPad, temp, 5);
sendData.vars.pad0 = 0;
//sendData.vars.pad1 = 0;
}
void loop()
{
sendData.vars.data0 = (256);
//sendData.vars.data1 = (512);
//sendData.vars.data2 = (1024);
Serial.write(sendData.buffer, sizeof(sensorData));
delay(100);
}
Python:
import serial
class SensorData:
def __init__(self, ser_obj, s_dict, p_start, p_len):
self.ser = ser_obj
self.sensor_buffer = s_dict
self.num_sensors = len(s_dict)
self.pad_start = p_start
self.pad_len = p_len
self.wait_for_beginning(p_start)
def poll(self):
for i in range(self.num_sensors):
tmp = self.ser_read()
tmp+=(self.ser_read()<<8)
print tmp
self.sensor_buffer.values()[i].append(tmp)
self.ser_read()
return self.sensor_buffer
def ser_read(self):
while True:
try:
data = ord(self.ser.read())
break
except:
continue
return data
def wait_for_beginning(self, start):
while True:
while(self.ser_read() != 0): continue
flag = 0
for i in range(1, self.pad_len):
if i == self.ser_read(): continue
else:
flag = 1
break
if flag: continue
else: break
def wait_for_end(self):
while True:
pad = self.ser_read()
if pad == self.pad_len-1:
break
#END OF CLASS
#main.py
def serial_poll( s_dict ):
dev = serial_init()
s = SensorData( dev, s_dict, 0, 5 )
while True:
sensor_buffer = s.poll()
s.wait_for_end()
print sensor_buffer
def serial_init():
ser = serial.Serial()
ser.baudrate = 9600
ser.port = '/dev/ttyACM0'
ser.open()
return ser
if __name__ == "__main__":
global sensor_buffer
sensor_buffer = { 'sensor1': [] }
serial_thread = threading.Thread( target=serial_poll, args=(sensor_buffer, ) )
serial_thread.daemon = True
serial_thread.start()
while True:
time.sleep( .1 )
I'm running the serial functions on a new thread because I have other things going on in this application. I'm basically trying to send some data that I have hard coded from the Arduino to a Linux computer. I have padding in between actual data to delimit it. At first I thought I was getting buffer overflows since each data buffer was more than 14 bytes long. I shortened it and the issue persisted. I then tried to add a delay since it might be sending data too fast. This didn't help either and now I'm out of ideas. If you need me to be more specific just let me know.