Created
February 3, 2014 14:48
-
-
Save pfalcon/8785113 to your computer and use it in GitHub Desktop.
MicroPython - cstruct example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <string.h> | |
#include <sys/socket.h> | |
#include <sys/types.h> | |
#include <netinet/in.h> | |
#include "nlr.h" | |
#include "misc.h" | |
#include "mpconfig.h" | |
#include "mpqstr.h" | |
#include "obj.h" | |
#include "stream.h" | |
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) | |
//int cstruct_find_field(const char *name, const char **arr, int size); | |
typedef int (*getter_fun_t)(void *p, int id); | |
typedef void (*setter_fun_t)(void *p, int id, int val); | |
void cstruct_load_attr(const char **fields, int num_fields, getter_fun_t get_field, mp_obj_t self_in, qstr attr, mp_obj_t *dest); | |
bool cstruct_store_attr(const char **fields, int num_fields, setter_fun_t set_field, mp_obj_t self_in, qstr attr, mp_obj_t value); | |
void cstruct_print(const char **fields, int num_fields, getter_fun_t get_field, | |
void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind); | |
typedef struct _mp_obj_sockaddr_in_t { | |
mp_obj_base_t base; | |
struct sockaddr_in cstruct; | |
} mp_obj_sockaddr_in_t; | |
enum { | |
ID_sin_family, | |
ID_sin_addr, | |
ID_sin_port, | |
}; | |
static const char *sockaddr_in_fields[] = { "sin_family", "sin_addr", "sin_port" }; | |
static int sockaddr_in_get_field(void *_s, int id) { | |
struct sockaddr_in *s = _s; | |
switch (id) { | |
case ID_sin_family: | |
return s->sin_family; break; | |
case ID_sin_addr: | |
return *(uint32_t*)&s->sin_addr; break; | |
case ID_sin_port: | |
return s->sin_port; break; | |
} | |
return -1; | |
} | |
static void sockaddr_in_set_field(void *_s, int id, int val) { | |
struct sockaddr_in *s = _s; | |
switch (id) { | |
case ID_sin_family: | |
s->sin_family = val; break; | |
case ID_sin_addr: | |
*(uint32_t*)&s->sin_addr = val; break; | |
case ID_sin_port: | |
s->sin_port = val; break; | |
} | |
} | |
static void sockaddr_in_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { | |
cstruct_load_attr(sockaddr_in_fields, ARRAY_SIZE(sockaddr_in_fields), sockaddr_in_get_field, self_in, attr, dest); | |
} | |
static bool sockaddr_in_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { | |
return cstruct_store_attr(sockaddr_in_fields, ARRAY_SIZE(sockaddr_in_fields), sockaddr_in_set_field, self_in, attr, value); | |
} | |
extern const mp_obj_type_t sockaddr_in_type; | |
static mp_obj_t sockaddr_in_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { | |
mp_obj_sockaddr_in_t *o = m_new(mp_obj_sockaddr_in_t, 1); | |
o->base.type = &sockaddr_in_type; | |
memset(&o->cstruct, 0, sizeof(o->cstruct)); | |
return (mp_obj_t)o; | |
} | |
static void sockaddr_in_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) { | |
cstruct_print(sockaddr_in_fields, ARRAY_SIZE(sockaddr_in_fields), sockaddr_in_get_field, print, env, o_in, kind); | |
} | |
static machine_int_t sockaddr_in_get_buffer(mp_obj_t o_in, buffer_info_t *bufinfo, int flags) { | |
mp_obj_sockaddr_in_t *o = o_in; | |
bufinfo->buf = &o->cstruct; | |
bufinfo->len = sizeof(o->cstruct); | |
return 0; | |
} | |
const mp_obj_type_t sockaddr_in_type = { | |
{ &mp_const_type }, | |
"sockaddr_in", | |
.print = sockaddr_in_print, | |
.make_new = sockaddr_in_make_new, | |
.load_attr = sockaddr_in_load_attr, | |
.store_attr = sockaddr_in_store_attr, | |
.buffer_p = { .get_buffer = sockaddr_in_get_buffer }, | |
}; | |
//------------------- | |
#include <string.h> | |
#include "misc.h" | |
#include "mpconfig.h" | |
#include "mpqstr.h" | |
#include "obj.h" | |
typedef int (*getter_fun_t)(void *p, int id); | |
typedef void (*setter_fun_t)(void *p, int id, int val); | |
static int cstruct_find_field(const char *name, const char **arr, int size) { | |
for (int i = 0; i < size; i++) { | |
if (!strcmp(arr[i], name)) { | |
return i; | |
} | |
} | |
return -1; | |
} | |
void cstruct_load_attr(const char **fields, int num_fields, getter_fun_t get_field, mp_obj_t self_in, qstr attr, mp_obj_t *dest) { | |
struct _mp_obj_base_t *self = self_in; | |
int id = cstruct_find_field(qstr_str(attr), fields, num_fields); | |
if (id < 0) { | |
return; | |
} | |
// Pass pointer to beyond _mp_obj_base_t, i.e. to cstruct | |
machine_int_t v = get_field(self + 1, id); | |
dest[1] = mp_obj_new_int(v); | |
} | |
bool cstruct_store_attr(const char **fields, int num_fields, setter_fun_t set_field, mp_obj_t self_in, qstr attr, mp_obj_t value) { | |
struct _mp_obj_base_t *self = self_in; | |
int id = cstruct_find_field(qstr_str(attr), fields, num_fields); | |
if (id < 0) { | |
return false; | |
} | |
machine_int_t v = mp_obj_get_int(value); | |
// Pass pointer to beyond _mp_obj_base_t, i.e. to cstruct | |
set_field(self + 1, id, v); | |
return true; | |
} | |
void cstruct_print(const char **fields, int num_fields, getter_fun_t get_field, | |
void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) { | |
struct _mp_obj_base_t *o = o_in; | |
print(env, o->type->name); | |
print(env, "("); | |
for (int i = 0; i < num_fields; i++) { | |
if (i > 0) { | |
print(env, ", "); | |
} | |
print(env, "%s=0x%x", fields[i], get_field(o + 1, i)); | |
} | |
print(env, ")"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment