#define PY_SSIZE_T_CLEAN #include "Python.h" #include #include #define FLUXOP_INDEX 1 #define FLUXOP_SPACE 2 #define FLUXOP_ASTABLE 3 /* bitarray.append(value) */ static PyObject *append_s; static int bitarray_append(PyObject *bitarray, PyObject *value) { PyObject *res = PyObject_CallMethodObjArgs( bitarray, append_s, value, NULL); if (res == NULL) return 0; Py_DECREF(res); return 1; } static PyObject * flux_to_bitcells(PyObject *self, PyObject *args) { /* Parameters */ PyObject *bit_array, *time_array, *revolutions; PyObject *index_iter, *flux_iter; double freq, clock_centre, clock_min, clock_max; double pll_period_adj, pll_phase_adj; /* Local variables */ PyObject *item; double clock, new_ticks, ticks, to_index; int zeros, nbits; if (!PyArg_ParseTuple(args, "OOOOOdddddd", &bit_array, &time_array, &revolutions, &index_iter, &flux_iter, &freq, &clock_centre, &clock_min, &clock_max, &pll_period_adj, &pll_phase_adj)) return NULL; nbits = 0; ticks = 0.0; clock = clock_centre; /* to_index = next(index_iter) */ item = PyIter_Next(index_iter); to_index = PyFloat_AsDouble(item); Py_DECREF(item); if (PyErr_Occurred()) return NULL; /* for x in flux_iter: */ assert(PyIter_Check(flux_iter)); while ((item = PyIter_Next(flux_iter)) != NULL) { double x = PyFloat_AsDouble(item); Py_DECREF(item); if (PyErr_Occurred()) return NULL; /* Gather enough ticks to generate at least one bitcell. */ ticks += x / freq; if (ticks < clock/2) continue; /* Clock out zero or more 0s, followed by a 1. */ for (zeros = 0; ; zeros++) { /* Check if we cross the index mark. */ to_index -= clock; if (to_index < 0) { if (PyList_Append(revolutions, PyLong_FromLong(nbits)) < 0) return NULL; nbits = 0; item = PyIter_Next(index_iter); to_index += PyFloat_AsDouble(item); Py_DECREF(item); if (PyErr_Occurred()) return NULL; } nbits += 1; ticks -= clock; if (PyList_Append(time_array, PyFloat_FromDouble(clock)) < 0) return NULL; if (ticks < clock/2) { if (!bitarray_append(bit_array, Py_True)) return NULL; break; } if (!bitarray_append(bit_array, Py_False)) return NULL; } /* PLL: Adjust clock frequency according to phase mismatch. */ if (zeros <= 3) { /* In sync: adjust clock by a fraction of the phase mismatch. */ clock += ticks * pll_period_adj; } else { /* Out of sync: adjust clock towards centre. */ clock += (clock_centre - clock) * pll_period_adj; } /* Clamp the clock's adjustment range. */ if (clock < clock_min) clock = clock_min; else if (clock > clock_max) clock = clock_max; /* PLL: Adjust clock phase according to mismatch. */ new_ticks = ticks * (1.0 - pll_phase_adj); if (PyList_SetItem(time_array, PyList_Size(time_array)-1, PyFloat_FromDouble(ticks - new_ticks)) < 0) return NULL; ticks = new_ticks; } Py_RETURN_NONE; } static int _read_28bit(uint8_t *p) { int x; x = (p[0] ) >> 1; x |= (p[1] & 0xfe) << 6; x |= (p[2] & 0xfe) << 13; x |= (p[3] & 0xfe) << 20; return x; } static PyObject * decode_flux(PyObject *self, PyObject *args) { /* Parameters */ Py_buffer bytearray; PyObject *res = NULL; /* bytearray buffer */ uint8_t *p; Py_ssize_t l; /* Local variables */ PyObject *flux, *index; long val, ticks, ticks_since_index; int i, opcode; if (!PyArg_ParseTuple(args, "y*", &bytearray)) return NULL; p = bytearray.buf; l = bytearray.len; /* assert dat[-1] == 0 */ if ((l == 0) || (p[l-1] != 0)) { PyErr_SetString(PyExc_ValueError, "Flux is not NUL-terminated"); PyBuffer_Release(&bytearray); return NULL; } /* len(dat) -= 1 */ l -= 1; /* flux, index = [], [] */ flux = PyList_New(0); index = PyList_New(0); /* ticks, ticks_since_index = 0, 0 */ ticks = 0; ticks_since_index = 0; while (l != 0) { i = *p++; if (i == 255) { if ((l -= 2) < 0) goto oos; opcode = *p++; switch (opcode) { case FLUXOP_INDEX: if ((l -= 4) < 0) goto oos; val = _read_28bit(p); p += 4; if (PyList_Append(index, PyLong_FromLong( ticks_since_index + ticks + val)) < 0) goto out; ticks_since_index = -(ticks + val); break; case FLUXOP_SPACE: if ((l -= 4) < 0) goto oos; ticks += _read_28bit(p); p += 4; break; default: PyErr_Format(PyExc_ValueError, "Bad opcode in flux stream (%d)", opcode); goto out; } } else { if (i < 250) { l -= 1; val = i; } else { if ((l -= 2) < 0) goto oos; val = 250 + (i - 250) * 255; val += *p++ - 1; } ticks += val; if (PyList_Append(flux, PyLong_FromLong(ticks)) < 0) goto out; ticks_since_index += ticks; ticks = 0; } } res = Py_BuildValue("OO", flux, index); out: PyBuffer_Release(&bytearray); Py_DECREF(flux); Py_DECREF(index); return res; oos: PyErr_SetString(PyExc_ValueError, "Unexpected end of flux"); goto out; } static PyMethodDef modulefuncs[] = { { "flux_to_bitcells", flux_to_bitcells, METH_VARARGS, NULL }, { "decode_flux", decode_flux, METH_VARARGS, NULL }, { NULL } }; static PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "optimised", 0, -1, modulefuncs, }; PyMODINIT_FUNC PyInit_optimised(void) { append_s = Py_BuildValue("s", "append"); return PyModule_Create(&moduledef); }