@@ -41,24 +41,31 @@ typedef struct
4141 hdlc_crc_t crc_type;
4242 int mtu;
4343 int window_size;
44+ int mode;
45+ int peers_count;
46+ int addr;
4447 void *buffer;
4548 PyObject *on_frame_send;
4649 PyObject *on_frame_read;
50+ PyObject *on_frame_read_ui;
4751 PyObject *on_connect_event;
4852 PyObject *read_func;
4953 PyObject *write_func;
5054 int error_flag;
5155} Fd;
5256
5357static PyMemberDef Fd_members[] = {
54- {" mtu" , T_INT , offsetof (Fd, mtu), 0 , " Maximum size of payload" }, {NULL } /* Sentinel */
58+ {" mtu" , T_INT , offsetof (Fd, mtu), 0 , " Maximum size of payload" },
59+ {" window_size" , T_INT , offsetof (Fd, window_size), 0 , " Sliding window size (1-7)" },
60+ {NULL } /* Sentinel */
5561};
5662
5763// ///////////////////////////// ALLOC/DEALLOC
5864
5965static void Fd_dealloc (Fd *self)
6066{
6167 Py_XDECREF (self->on_frame_read );
68+ Py_XDECREF (self->on_frame_read_ui );
6269 Py_XDECREF (self->on_frame_send );
6370 Py_XDECREF (self->on_connect_event );
6471 Py_XDECREF (self->read_func );
@@ -73,11 +80,15 @@ static int Fd_init(Fd *self, PyObject *args, PyObject *kwds)
7380 self->crc_type = HDLC_CRC_16 ;
7481 self->on_frame_send = NULL ;
7582 self->on_frame_read = NULL ;
83+ self->on_frame_read_ui = NULL ;
7684 self->on_connect_event = NULL ;
7785 self->read_func = NULL ;
7886 self->write_func = NULL ;
7987 self->mtu = 1500 ;
8088 self->window_size = 7 ;
89+ self->mode = TINY_FD_MODE_ABM ;
90+ self->peers_count = 0 ;
91+ self->addr = 0 ;
8192 self->error_flag = 0 ;
8293 return 0 ;
8394}
@@ -104,10 +115,31 @@ static void on_frame_read(void *user_data, uint8_t addr, uint8_t *data, int len)
104115 PyGILState_STATE gstate;
105116 gstate = PyGILState_Ensure ();
106117
118+ PyObject *arg_addr = PyLong_FromLong ((long )addr);
107119 PyObject *arg = PyByteArray_FromStringAndSize ((const char *)data, (Py_ssize_t)len);
108- PyObject *temp = PyObject_CallFunctionObjArgs (self->on_frame_read , arg, NULL );
109- Py_XDECREF (temp); // Dereference result
110- Py_DECREF (arg); // We do not need ByteArray anymore
120+ PyObject *temp = PyObject_CallFunctionObjArgs (self->on_frame_read , arg_addr, arg, NULL );
121+ Py_XDECREF (temp);
122+ Py_DECREF (arg);
123+ Py_DECREF (arg_addr);
124+
125+ PyGILState_Release (gstate);
126+ }
127+ }
128+
129+ static void on_frame_read_ui (void *user_data, uint8_t addr, uint8_t *data, int len)
130+ {
131+ Fd *self = (Fd *)user_data;
132+ if ( self->on_frame_read_ui )
133+ {
134+ PyGILState_STATE gstate;
135+ gstate = PyGILState_Ensure ();
136+
137+ PyObject *arg_addr = PyLong_FromLong ((long )addr);
138+ PyObject *arg = PyByteArray_FromStringAndSize ((const char *)data, (Py_ssize_t)len);
139+ PyObject *temp = PyObject_CallFunctionObjArgs (self->on_frame_read_ui , arg_addr, arg, NULL );
140+ Py_XDECREF (temp);
141+ Py_DECREF (arg);
142+ Py_DECREF (arg_addr);
111143
112144 PyGILState_Release (gstate);
113145 }
@@ -121,10 +153,12 @@ static void on_frame_send(void *user_data, uint8_t addr, const uint8_t *data, in
121153 PyGILState_STATE gstate;
122154 gstate = PyGILState_Ensure ();
123155
156+ PyObject *arg_addr = PyLong_FromLong ((long )addr);
124157 PyObject *arg = PyByteArray_FromStringAndSize ((const char *)data, (Py_ssize_t)len);
125- PyObject *temp = PyObject_CallFunctionObjArgs (self->on_frame_send , arg, NULL );
126- Py_XDECREF (temp); // Dereference result
127- Py_DECREF (arg); // We do not need ByteArray anymore
158+ PyObject *temp = PyObject_CallFunctionObjArgs (self->on_frame_send , arg_addr, arg, NULL );
159+ Py_XDECREF (temp);
160+ Py_DECREF (arg);
161+ Py_DECREF (arg_addr);
128162
129163 PyGILState_Release (gstate);
130164 }
@@ -160,15 +194,21 @@ static PyObject *Fd_begin(Fd *self)
160194 init.on_read_cb = on_frame_read;
161195 init.on_send_cb = on_frame_send;
162196 init.on_connect_event_cb = on_connect_event;
197+ init.on_read_ui_cb = on_frame_read_ui;
163198 init.crc_type = self->crc_type ;
164- init.buffer_size = tiny_fd_buffer_size_by_mtu_ex (1 , self->mtu , self->window_size , init.crc_type , 2 );
199+ init.buffer_size = tiny_fd_buffer_size_by_mtu_ex (
200+ self->peers_count > 0 ? self->peers_count : 1 ,
201+ self->mtu , self->window_size , init.crc_type , 2 );
165202 self->buffer = PyObject_Malloc (init.buffer_size );
166203 init.buffer = self->buffer ;
167204 init.send_timeout = 1000 ;
168205 init.retry_timeout = 200 ;
169206 init.retries = 2 ;
170207 init.window_frames = self->window_size ;
171208 init.mtu = self->mtu ;
209+ init.mode = (uint8_t )self->mode ;
210+ init.peers_count = (uint8_t )self->peers_count ;
211+ init.addr = (uint8_t )self->addr ;
172212 int result = tiny_fd_init (&self->handle , &init);
173213 return PyLong_FromLong ((long )result);
174214}
@@ -372,6 +412,69 @@ static PyObject *Fd_get_status(Fd *self)
372412 return PyLong_FromLong ((long )result);
373413}
374414
415+ static PyObject *Fd_send_to (Fd *self, PyObject *args)
416+ {
417+ int addr;
418+ Py_buffer buffer{};
419+ if ( !PyArg_ParseTuple (args, " is*" , &addr, &buffer) )
420+ {
421+ return NULL ;
422+ }
423+ int result;
424+ Py_BEGIN_ALLOW_THREADS;
425+ result = tiny_fd_send_packet_to (self->handle , (uint8_t )addr, buffer.buf , buffer.len , 1000 );
426+ Py_END_ALLOW_THREADS;
427+ PyBuffer_Release (&buffer);
428+ return PyLong_FromLong ((long )result);
429+ }
430+
431+ static PyObject *Fd_register_peer (Fd *self, PyObject *args)
432+ {
433+ int addr;
434+ if ( !PyArg_ParseTuple (args, " i" , &addr) )
435+ {
436+ return NULL ;
437+ }
438+ int result = tiny_fd_register_peer (self->handle , (uint8_t )addr);
439+ return PyLong_FromLong ((long )result);
440+ }
441+
442+ static PyObject *Fd_send_ui (Fd *self, PyObject *args)
443+ {
444+ Py_buffer buffer{};
445+ if ( !PyArg_ParseTuple (args, " s*" , &buffer) )
446+ {
447+ return NULL ;
448+ }
449+ int result = tiny_fd_send_ui_packet (self->handle , buffer.buf , buffer.len );
450+ PyBuffer_Release (&buffer);
451+ return PyLong_FromLong ((long )result);
452+ }
453+
454+ static PyObject *Fd_send_ui_to (Fd *self, PyObject *args)
455+ {
456+ int addr;
457+ Py_buffer buffer{};
458+ if ( !PyArg_ParseTuple (args, " is*" , &addr, &buffer) )
459+ {
460+ return NULL ;
461+ }
462+ int result = tiny_fd_send_ui_packet_to (self->handle , (uint8_t )addr, buffer.buf , buffer.len );
463+ PyBuffer_Release (&buffer);
464+ return PyLong_FromLong ((long )result);
465+ }
466+
467+ static PyObject *Fd_set_ka_timeout (Fd *self, PyObject *args)
468+ {
469+ unsigned int timeout;
470+ if ( !PyArg_ParseTuple (args, " I" , &timeout) )
471+ {
472+ return NULL ;
473+ }
474+ tiny_fd_set_ka_timeout (self->handle , (uint32_t )timeout);
475+ Py_RETURN_NONE;
476+ }
477+
375478/*
376479void tiny_fd_set_ka_timeout ( tiny_fd_handle_t handle,
377480 uint32_t keep_alive
@@ -426,7 +529,22 @@ static int Fd_set_on_connect_event(Fd *self, PyObject *value, void *closure)
426529 return 0 ;
427530}
428531
429- static PyObject *Fd_get_crc (Fd *self, void *closure)
532+ static PyObject *Fd_get_on_read_ui (Fd *self, void *closure)
533+ {
534+ Py_INCREF (self->on_frame_read_ui );
535+ return self->on_frame_read_ui ;
536+ }
537+
538+ static int Fd_set_on_read_ui (Fd *self, PyObject *value, void *closure)
539+ {
540+ PyObject *tmp = self->on_frame_read_ui ;
541+ Py_INCREF (value);
542+ self->on_frame_read_ui = value;
543+ Py_XDECREF (tmp);
544+ return 0 ;
545+ }
546+
547+ static PyObject* Fd_get_crc (Fd *self, void * closure)
430548{
431549 return PyLong_FromLong ( self->crc_type );
432550}
@@ -449,15 +567,79 @@ static int Fd_set_crc(Fd *self, PyObject *value)
449567 {
450568 PyErr_Format (PyExc_RuntimeError, " Allowable CRC values are: 0 (AUTO), 8, 16, 32, 255 (OFF)" );
451569 }
452- return result/* 0 on success, -1 on failure with error set. */ ;
570+ return result;
571+ }
572+
573+ static PyObject *Fd_get_mode (Fd *self, void *closure)
574+ {
575+ return PyLong_FromLong (self->mode );
576+ }
577+
578+ static int Fd_set_mode (Fd *self, PyObject *value, void *closure)
579+ {
580+ if ( value && PyLong_Check (value) )
581+ {
582+ int temp = PyLong_AsLong (value);
583+ if ( temp == TINY_FD_MODE_ABM || temp == TINY_FD_MODE_NRM )
584+ {
585+ self->mode = temp;
586+ return 0 ;
587+ }
588+ }
589+ PyErr_Format (PyExc_RuntimeError, " Allowable mode values are: 0 (ABM), 1 (NRM)" );
590+ return -1 ;
591+ }
592+
593+ static PyObject *Fd_get_peers_count (Fd *self, void *closure)
594+ {
595+ return PyLong_FromLong (self->peers_count );
596+ }
597+
598+ static int Fd_set_peers_count (Fd *self, PyObject *value, void *closure)
599+ {
600+ if ( value && PyLong_Check (value) )
601+ {
602+ int temp = PyLong_AsLong (value);
603+ if ( temp >= 0 && temp <= 63 )
604+ {
605+ self->peers_count = temp;
606+ return 0 ;
607+ }
608+ }
609+ PyErr_Format (PyExc_RuntimeError, " peers_count must be 0-63" );
610+ return -1 ;
611+ }
612+
613+ static PyObject *Fd_get_addr (Fd *self, void *closure)
614+ {
615+ return PyLong_FromLong (self->addr );
616+ }
617+
618+ static int Fd_set_addr (Fd *self, PyObject *value, void *closure)
619+ {
620+ if ( value && PyLong_Check (value) )
621+ {
622+ int temp = PyLong_AsLong (value);
623+ if ( temp >= 0 && temp <= 62 )
624+ {
625+ self->addr = temp;
626+ return 0 ;
627+ }
628+ }
629+ PyErr_Format (PyExc_RuntimeError, " addr must be 0 (primary) or 1-62 (secondary)" );
630+ return -1 ;
453631}
454632
455633static PyGetSetDef Fd_getsetters[] = {
456- {" on_read" , (getter)Fd_get_on_read, (setter)Fd_set_on_read, " Callback for incoming messages" , NULL },
457- {" on_send" , (getter)Fd_get_on_send, (setter)Fd_set_on_send, " Callback for successfully sent messages" , NULL },
634+ {" on_read" , (getter)Fd_get_on_read, (setter)Fd_set_on_read, " Callback for incoming I-frames: func(addr, data)" , NULL },
635+ {" on_read_ui" , (getter)Fd_get_on_read_ui, (setter)Fd_set_on_read_ui, " Callback for incoming UI frames: func(addr, data)" , NULL },
636+ {" on_send" , (getter)Fd_get_on_send, (setter)Fd_set_on_send, " Callback for successfully sent messages: func(addr, data)" , NULL },
458637 {" on_connect_event" , (getter)Fd_get_on_connect_event, (setter)Fd_set_on_connect_event,
459- " Callback for connection status change events" , NULL },
460- {" crc" , (getter)Fd_get_crc, (setter)Fd_set_crc, " CRC value" , NULL },
638+ " Callback for connection status change: func(addr, connected)" , NULL },
639+ {" crc" , (getter)Fd_get_crc, (setter)Fd_set_crc, " CRC type: 0 (AUTO), 8, 16, 32, 255 (OFF)" , NULL },
640+ {" mode" , (getter)Fd_get_mode, (setter)Fd_set_mode, " Protocol mode: 0 (ABM), 1 (NRM)" , NULL },
641+ {" peers_count" , (getter)Fd_get_peers_count, (setter)Fd_set_peers_count, " Max peers (0-63, NRM primary only)" , NULL },
642+ {" addr" , (getter)Fd_get_addr, (setter)Fd_set_addr, " Station address: 0 (primary) or 1-62 (secondary)" , NULL },
461643 {NULL } /* Sentinel */
462644};
463645
@@ -467,12 +649,17 @@ static PyMethodDef Fd_methods[] = {
467649 {" begin" , (PyCFunction)Fd_begin, METH_NOARGS , " Initializes Fd protocol" },
468650 {" end" , (PyCFunction)Fd_end, METH_NOARGS , " Stops Fd protocol" },
469651 {" send" , (PyCFunction)Fd_send, METH_VARARGS , " Sends new message to remote side" },
652+ {" send_to" , (PyCFunction)Fd_send_to, METH_VARARGS , " Sends message to specific peer: send_to(addr, data)" },
653+ {" send_ui" , (PyCFunction)Fd_send_ui, METH_VARARGS , " Sends UI (connectionless) frame" },
654+ {" send_ui_to" , (PyCFunction)Fd_send_ui_to, METH_VARARGS , " Sends UI frame to specific peer: send_ui_to(addr, data)" },
655+ {" register_peer" , (PyCFunction)Fd_register_peer, METH_VARARGS , " Registers peer address (NRM primary)" },
470656 {" disconnect" , (PyCFunction)Fd_disconnect, METH_NOARGS , " Sends disconnect frame" },
471657 {" rx" , (PyCFunction)Fd_rx, METH_VARARGS , " Passes rx data" },
472658 {" tx" , (PyCFunction)Fd_tx, METH_VARARGS , " Fills specified buffer with tx data" },
473659 {" run_rx" , (PyCFunction)Fd_run_rx, METH_VARARGS , " Reads data from user callback and parses them" },
474660 {" run_tx" , (PyCFunction)Fd_run_tx, METH_VARARGS , " Writes data to user callback" },
475661 {" get_status" , (PyCFunction)Fd_get_status, METH_NOARGS , " Get connection status" },
662+ {" set_ka_timeout" , (PyCFunction)Fd_set_ka_timeout, METH_VARARGS , " Set keep-alive timeout in ms" },
476663 {NULL } /* Sentinel */
477664};
478665
0 commit comments