#include
#include "yahdlc.h"
#define MAX_FRAME_PAYLOAD 512
#define HEADERS_LENGTH 8
#define TOTAL_FRAME_LENGTH MAX_FRAME_PAYLOAD + HEADERS_LENGTH
static PyObject *Yahdlc_MessageError;
static PyObject *Yahdlc_FCSError;
/* ---------- yahdlc functions ---------- */
/**
* Retrieves data from the specified buffer containing the HDLC frame.
*/
static PyObject *get_data(PyObject *self, PyObject *args)
{
int ret;
const char *frame_data;
char recv_data[TOTAL_FRAME_LENGTH];
unsigned int buf_length = 0, recv_length = 0;
yahdlc_control_t control;
if (!PyArg_ParseTuple(args, "s#", &frame_data, &buf_length))
return NULL;
if (buf_length > TOTAL_FRAME_LENGTH)
{
PyErr_SetString(PyExc_ValueError, "buffer too long");
return NULL;
}
ret = yahdlc_get_data(&control, frame_data, buf_length, recv_data, &recv_length);
// If success.
if (ret >= 0)
{
PyObject *t;
t = PyTuple_New(4);
PyTuple_SetItem(t, 0, PyBytes_FromStringAndSize(recv_data, recv_length));
PyTuple_SetItem(t, 1, PyLong_FromUnsignedLong(control.frame));
PyTuple_SetItem(t, 2, PyLong_FromUnsignedLong(control.seq_no));
PyTuple_SetItem(t, 3, PyLong_FromUnsignedLong(ret));
return t;
}
else if (ret == -EINVAL)
{
PyErr_SetString(PyExc_ValueError, "invalid parameter");
return NULL;
}
else if (ret == -ENOMSG)
{
PyErr_SetString(Yahdlc_MessageError, "invalid message");
return NULL;
}
// If the FCS is not valid, we return the sequence number
// to be sent back as NACK.
else if (ret == -EIO)
{
PyErr_SetObject(Yahdlc_FCSError, PyLong_FromUnsignedLong(control.seq_no));
return NULL;
}
else
{
PyErr_SetString(PyExc_RuntimeError, "unknown error");
return NULL;
}
}
/**
* Resets the values used by the 'yahdlc_get_data' function
* to keep track of the received buffers.
*/
static PyObject *get_data_reset(PyObject *self, PyObject *args)
{
yahdlc_get_data_reset();
Py_RETURN_NONE;
}
/**
* Creates an HDLC frame with the specified data buffer.
*/
static PyObject *frame_data(PyObject *self, PyObject *args)
{
int ret;
const char *send_data;
char frame_data[TOTAL_FRAME_LENGTH];
unsigned int data_length = 0, frame_length = 0, frame_type = YAHDLC_FRAME_DATA, seq_no = 0;
yahdlc_control_t control;
if (!PyArg_ParseTuple(args, "s#|II", &send_data, &data_length, &frame_type, &seq_no))
return NULL;
if (data_length > MAX_FRAME_PAYLOAD)
{
PyErr_SetString(PyExc_ValueError, "data too long");
return NULL;
}
else if (frame_type != YAHDLC_FRAME_DATA && frame_type != YAHDLC_FRAME_ACK && frame_type != YAHDLC_FRAME_NACK)
{
PyErr_SetString(PyExc_ValueError, "bad frame type");
return NULL;
}
else if (seq_no > 7)
{
PyErr_SetString(PyExc_ValueError, "invalid sequence number");
return NULL;
}
control.frame = frame_type;
control.seq_no = seq_no;
ret = yahdlc_frame_data(&control, send_data, data_length, frame_data, &frame_length);
// If success.
if (ret == 0)
return PyBytes_FromStringAndSize(frame_data, frame_length);
else
{
PyErr_SetString(PyExc_ValueError, "invalid parameter");
return NULL;
}
}
/* ---------- Settings ---------- */
/**
* Python module's methods.
*/
static PyMethodDef YahdlcMethods[] = {
{"get_data", get_data, METH_VARARGS, "Retrieves data from the specified buffer containing the HDLC frame."},
{"get_data_reset", get_data_reset, METH_VARARGS, "Resets the values used by the 'get_data' method to keep track of the received buffers."},
{"frame_data", frame_data, METH_VARARGS, "Creates an HDLC frame with the specified data buffer."},
{NULL, NULL, 0, NULL}
};
/**
* Python module itself.
*/
static struct PyModuleDef yahdlc_module =
{
PyModuleDef_HEAD_INIT,
"yahdlc",
"HDLC implementation",
-1,
YahdlcMethods
};
/**
* Initialises the Python module.
*/
PyMODINIT_FUNC PyInit_yahdlc(void)
{
PyObject *m;
m = PyModule_Create(&yahdlc_module);
if (m == NULL)
return NULL;
Yahdlc_MessageError = PyErr_NewException("yahdlc.MessageError", NULL, NULL);
Py_INCREF(Yahdlc_MessageError);
PyModule_AddObject(m, "MessageError", Yahdlc_MessageError);
Yahdlc_FCSError = PyErr_NewException("yahdlc.FCSError", NULL, NULL);
Py_INCREF(Yahdlc_FCSError);
PyModule_AddObject(m, "FCSError", Yahdlc_FCSError);
PyModule_AddIntConstant(m, "FRAME_DATA", YAHDLC_FRAME_DATA);
PyModule_AddIntConstant(m, "FRAME_ACK", YAHDLC_FRAME_ACK);
PyModule_AddIntConstant(m, "FRAME_NACK", YAHDLC_FRAME_NACK);
return m;
}