# HG changeset patch # User jfp <jf.pieronne@laposte.net> # Date 1737726756 -3600 # Fri Jan 24 14:52:36 2025 +0100 # Node ID 05a16119f8153930910f6970b260c37885b74a3d # Parent ee507f63361f98ee7b34bf04a6251687bc83aadb Fix ptd modules, use separate buffers diff --git a/python/local/ovms_module/ovms/ptd/__init__.py b/python/local/ovms_module/ovms/ptd/__init__.py --- a/python/local/ovms_module/ovms/ptd/__init__.py +++ b/python/local/ovms_module/ovms/ptd/__init__.py @@ -270,12 +270,12 @@ self._to_screen(res) return res - def write(self, string: bytes | str) -> str: + def write(self, string: bytes | str, echo: bool=False) -> str: """Write to the pseudo terminal, return the echo string""" wres = "" n = Ptd.tty_typahdsz - 8 for i in range(0, len(string), n): - _, res = _vmsptd.write(self.ptd, string[i:i+n]) + _, res = _vmsptd.write(self.ptd, string[i:i+n], echo) if isinstance(res, bytes): res = res.decode("iso-8859-15") elif not isinstance(res, str): @@ -284,14 +284,14 @@ self._to_screen(res) return wres - def writeln(self, string: bytes | str): + def writeln(self, string: bytes | str, echo: bool=False): """Write to the pseudo terminal the command and send a '\\r' character""" if not isinstance(string, (bytes, str)): raise ValueError(f"{string} should be bytes or str") return ( - self.write(string + b"\r") + self.write(string + b"\r", echo) if isinstance(string, bytes) - else self.write(string + "\r") + else self.write(string + "\r", echo) ) def read_until( @@ -432,12 +432,12 @@ """ return self.expect(list + [self.prompt], timeout) - def execute(self, cmd: bytes | str) -> Tuple[str, List[str]]: + def execute(self, cmd: bytes | str, echo: bool=False) -> Tuple[str, List[str]]: """Execute synchronously a command, so wait for the prompt Return the echo string and the list of all the results of the command including the final prompt. """ - resw = self.writeln(cmd) + resw = self.writeln(cmd, echo) resr = self.read_until_prompt() return resw, resr diff --git a/python/local/ovms_module/ovms/ptd/_vmsptd.pyi b/python/local/ovms_module/ovms/ptd/_vmsptd.pyi --- a/python/local/ovms_module/ovms/ptd/_vmsptd.pyi +++ b/python/local/ovms_module/ovms/ptd/_vmsptd.pyi @@ -41,8 +41,9 @@ """status, res = readw(handler)""" ... -def write(handler: PtdHandler, wrstr: bytes | str) -> Tuple[int, bytes]: - """status, res = write(handler, wrstr)""" +def write(handler: PtdHandler, wrstr: bytes | str, echo: bool=True + ) -> Tuple[int, bytes]: + """status, res = write(handler, wrstr, echo=True)""" ... def set_event_notification(handler: PtdHandler) -> int: diff --git a/python/local/ovms_module/ovms/ptd/_vmsptd.pyx b/python/local/ovms_module/ovms/ptd/_vmsptd.pyx --- a/python/local/ovms_module/ovms/ptd/_vmsptd.pyx +++ b/python/local/ovms_module/ovms/ptd/_vmsptd.pyx @@ -15,10 +15,12 @@ cdef extern from *: pass +from libc.stdint cimport uintptr_t + cdef extern from "ovptd.h" nogil: enum: DSC_K_DTYPE_T "DSC$K_DTYPE_T" enum: DSC_K_CLASS_S "DSC$K_CLASS_S" - enum: _SC_PAGE_SIZE + enum: _SC_PAGESIZE enum: EFN_C_ENF "EFN$C_ENF" enum: SS__NORMAL "SS$_NORMAL" enum: SS__TIMEOUT "SS$_TIMEOUT" @@ -66,17 +68,23 @@ ctypedef struct ptd_handler: unsigned short channel - int nbpages + int nbpagelets int buflen unsigned int efn int read_status int timer_status int read_start_read + int maxbuf + char* read_buf + char* echo_buf + char* write_buf VA_RANGE inadr ctypedef struct DevChar: pass + enum: SYI__MAXBUF "SYI$_MAXBUF" + void DESCSTR(...) void INITDEVCHAR(...) void cgetmsg(int, char*, int) @@ -86,6 +94,7 @@ int lib_get_ef "lib$get_ef" (...) int lib_get_vm_page "lib$get_vm_page" (...) int lib_free_vm_page "lib$free_vm_page" (...) + int lib_getsyi "lib$getsyi" (...) int sys_bintim "sys$bintim" (...) int sys_setimr "sys$setimr" (...) int sys_hiber "sys$hiber" (...) @@ -102,6 +111,7 @@ void read_timeout_ast (...) void read_start_read_ast (...) void read_end_read_ast (...) + void* align_pointer (...) from libc.stdio cimport printf, puts, sprintf @@ -120,9 +130,12 @@ property channel: def __get__(self): return self.handler.channel - property nbpages: + property nbpagelets: def __get__(self): - return self.handler.nbpages + return self.handler.nbpagelets + property maxbuf: + def __get__(self): + return self.handler.maxbuf property buflen: def __get__(self): return self.handler.buflen @@ -284,31 +297,41 @@ "status, handler = create(acmode=0, charbuff=None)" cdef unsigned short s; cdef char* inadr[2] - cdef int pgsize = sysconf(_SC_PAGE_SIZE) - cdef int nbpages = <int>(6 * pgsize / 512) # 4 + 1 data + 1 guard pages + cdef int pgsize = sysconf(_SC_PAGESIZE) cdef char* ptrc cdef PtdHandler handler = PtdHandler() cdef DevChar* devchar cdef unsigned short buflen + cdef int item_code = SYI__MAXBUF + cdef int maxbuf + s = lib_getsyi(&item_code, &maxbuf) + cdef int nbpages = 6 # 4 + 1 data + 1 guard pages + cdef int nbpagelets = <int>(nbpages * pgsize / 512) + + checkStatus(s); if charbuff is None: devchar = NULL buflen = 0 else: devchar = &(charbuff.devchar) buflen = sizeof(charbuff.devchar) - s = lib_get_vm_page(&nbpages, &(handler.handler)) + s = lib_get_vm_page(&nbpagelets, &(handler.handler)) checkStatus(s) - ptrc = <char *>handler.handler + pgsize + pgsize - 1 # keep one data page - ptrc = ptrc - <unsigned int>ptrc % pgsize - handler.handler.nbpages = nbpages + ptrc = <char *>align_pointer(<char *>handler.handler + pgsize, pgsize, 1) # align to page boundary, keep one data page + handler.handler.read_buf = ptrc + handler.handler.write_buf = ptrc + maxbuf + handler.handler.echo_buf = ptrc + 2 * maxbuf + handler.handler.nbpagelets = nbpagelets + handler.handler.maxbuf = maxbuf handler.handler.inadr.va_range_ps_start_va = ptrc - handler.handler.buflen = pgsize * 4 - handler.handler.inadr.va_range_ps_end_va = ptrc + handler.handler.buflen - 1 + handler.handler.buflen = buflen + handler.handler.inadr.va_range_ps_end_va = <char *>align_pointer(<char *>handler.handler + nbpagelets * 512 - 1, + pgsize, 0) - 1 handler.handler.read_status = 0 handler.handler.timer_status = 0 s = lib_get_ef(<unsigned int *>&(handler.handler.efn)) if s & 1 == 0: - lib_free_vm_page(<int *>&(handler.handler.nbpages), + lib_free_vm_page(<int *>&(handler.handler.nbpagelets), &(handler.handler)) checkStatus(s) s = ptd_create(<unsigned short*>&(handler.handler.channel), acmode, @@ -316,7 +339,7 @@ <VA_RANGE *>&(handler.handler.inadr)) if s & 1 == 0: lib_free_ef(<unsigned int *>&(handler.handler.efn)) - lib_free_vm_page(<int *>&(handler.handler.nbpages), + lib_free_vm_page(<int *>&(handler.handler.nbpagelets), &(handler.handler)) checkStatus(s) return s, handler @@ -330,7 +353,7 @@ checkStatus(s) s = lib_free_ef(<unsigned int *>&(handler.handler.efn)) checkStatus(s) - s = lib_free_vm_page(<int *>&(handler.handler.nbpages), + s = lib_free_vm_page(<int *>&(handler.handler.nbpagelets), &(handler.handler)) return s @@ -344,15 +367,16 @@ s = sys_hiber() s = SS__NORMAL handler.handler.read_status = 0 + (<unsigned short *>(handler.handler.inadr.va_range_ps_start_va))[0] = 0 with nogil: s = ptd_readw(EFN_C_ENF, handler.handler.channel, 0, 0, - handler.handler.inadr.va_range_ps_start_va, - handler.handler.buflen - 4) + handler.handler.read_buf, + handler.handler.maxbuf - 4) checkStatus(s) - s = (<unsigned short *>(handler.handler.inadr.va_range_ps_start_va))[0] + s = (<unsigned short *>(handler.handler.read_buf))[0] checkStatus(s) handler.handler.read_status = 0 - cdef char* buf = <char *>(handler.handler.inadr.va_range_ps_start_va) + 4 + cdef char* buf = <char *>(handler.handler.read_buf) + 4 cdef unsigned short* retlenPtr = <unsigned short *>(buf - 2) return s, buf[:retlenPtr[0]] @@ -385,46 +409,56 @@ with nogil: s = ptd_read(EFN_C_ENF, handler.handler.channel, read_ast, <int>handler.handler, - handler.handler.inadr.va_range_ps_start_va, - handler.handler.buflen - 4) + handler.handler.read_buf, + handler.handler.maxbuf - 4) checkStatus(s) while ((handler.handler.read_status == 1) and (handler.handler.timer_status == 1)): s = sys_hiber() if handler.handler.timer_status == 2: handler.handler.timer_status = 0 + handler.handler.read_status = 0 return SS__TIMEOUT, None - cdef char* buf = <char *>(handler.handler.inadr.va_range_ps_start_va) + 4 + s = (<unsigned short *>(handler.handler.read_buf))[0] + checkStatus(s) + cdef char* buf = <char *>(handler.handler.read_buf) + 4 cdef unsigned short* retlenPtr = <unsigned short *>(buf - 2) + handler.handler.timer_status = 0 handler.handler.read_status = 0 return s, buf[:retlenPtr[0]] -def write(PtdHandler handler, wrtstr): - "status, res = write(handler, wrstr)" +def write(PtdHandler handler, wrtstr, echo=False): + "status, res = write(handler, wrstr, echo=False)" wrtstr = getstr(wrtstr) cdef char* wrtstrPtr = wrtstr cdef int wlen = len(wrtstr) cdef unsigned short s; - if wlen > 1024: - raise ValueError('Invalid wrtstr length, maximum is 1024') - cdef char* wrtbuf = <char *>(handler.handler.inadr.va_range_ps_start_va) + cdef int with_echo; + with_echo = echo + if wlen > handler.handler.maxbuf - 4: + raise ValueError(f'Invalid wrtstr length, maximum is {handler.handler.maxbuf - 4}') + cdef char* wrtbuf = <char *>(handler.handler.write_buf) cdef char* readbuf = \ - <char *>(handler.handler.inadr.va_range_ps_start_va) + 1024 + <char *>(handler.handler.echo_buf) + cdef char* buf = <char *>(readbuf) + 4 + cdef unsigned short* retlenPtr = <unsigned short *>(buf - 2) memset(wrtbuf, 4, 0) strncpy(wrtbuf + 4, wrtstrPtr, wlen) + memset(readbuf, 4, 0) if handler.handler.read_status != 0: cancel(handler) with nogil: s = ptd_write(handler.handler.channel, 0, 0, - handler.handler.inadr.va_range_ps_start_va, wlen, readbuf, - handler.handler.buflen - 1024 - 4) + handler.handler.write_buf, wlen, readbuf if with_echo else NULL, + handler.handler.maxbuf - 4 if with_echo else 0) + checkStatus(s) + s = (<unsigned short *>(wrtbuf))[0] checkStatus(s) - s = (<unsigned short *>(handler.handler.inadr.va_range_ps_start_va))[0] - # if s != 0: - # checkStatus(s) - cdef char* buf = <char *>(handler.handler.inadr.va_range_ps_start_va) + 4 - cdef unsigned short* retlenPtr = <unsigned short *>(buf - 2) - return s, buf[:retlenPtr[0]] + if with_echo: + s = (<unsigned short *>(readbuf))[0] + checkStatus(s) + return s, buf[:retlenPtr[0]] + return s, buf[:0] def set_event_notification(PtdHandler handler): "status = set_event_notification(handler)" @@ -446,4 +480,4 @@ ) checkStatus(s) - return s \ No newline at end of file + return s diff --git a/python/local/ovms_module/ovms/ptd/ovptd.h b/python/local/ovms_module/ovms/ptd/ovptd.h --- a/python/local/ovms_module/ovms/ptd/ovptd.h +++ b/python/local/ovms_module/ovms/ptd/ovptd.h @@ -5,6 +5,7 @@ #include <stdio.h> #include <string.h> #include <unistd.h> +#include <inttypes.h> #include <descrip.h> #include <gen64def.h> @@ -22,6 +23,7 @@ #include <starlet.h> #include <afrdef.h> #include <ssdef.h> +#include <syidef.h> #include <stsdef.h> #include <ttdef.h> #include <tt2def.h> @@ -62,7 +64,7 @@ typedef volatile struct { unsigned short channel; - int nbpages; + int nbpagelets; int buflen; unsigned int efn; int read_status; /* 0: no IO, 1: IO started, 2: IO finished */ @@ -70,6 +72,10 @@ int read_start_read; /* 0: no read request 1: the pseudoterminal is starting an application's read request.*/ + int maxbuf; + char* read_buf; + char* echo_buf; + char* write_buf; VA_RANGE inadr; } ptd_handler; @@ -114,14 +120,14 @@ } if (ptr->timer_status != 0) { sys$cantim((unsigned __int64)ptr, 0); - ptr->timer_status = 0; + // ptr->timer_status = 0; } } static void read_timeout_ast(ptd_handler* ptr) { ptr->timer_status = 2; ptd$cancel(ptr->channel); - ptr->read_status = 0; + // ptr->read_status = 0; sys$wake(0, 0); } @@ -135,4 +141,29 @@ // sys$wake(0, 0); } +void* align_pointer(char* ptr, size_t page_size, int align_up) { + /* + * Aligns a pointer to a page boundary (lower or upper). + * + * Parameters: + * ptr - The initial pointer (char*). + * page_size - The size of a memory page in bytes. + * align_up - If non-zero, aligns to the upper page boundary. + * If zero, aligns to the lower page boundary. + * + * Returns: + * A pointer aligned to the specified page boundary (void*). + */ + + // Convert the pointer to an integer for alignment calculations + uintptr_t addr = (uintptr_t)ptr; + + if (align_up) { + // Align to the upper page boundary + return (void*)((addr + (page_size - 1)) & ~(page_size - 1)); + } else { + // Align to the lower page boundary + return (void*)(addr & ~(page_size - 1)); + } +} #endif