Edouard@592: #!/usr/bin/env python
Edouard@592: # -*- coding: utf-8 -*-
Edouard@592: #
andrej@1667: # See COPYING.Runtime file for copyrights details.
Edouard@592: #
andrej@1881: 
andrej@1783: from ctypes import *
andrej@1783: from datetime import timedelta as td
andrej@1783: 
Edouard@592: class IEC_STRING(Structure):
Edouard@592:     """
Edouard@592:     Must be changed according to changes in iec_types.h
Edouard@592:     """
Edouard@592:     _fields_ = [("len", c_uint8),
Edouard@1433:                 ("body", c_char * 126)]
Edouard@592: 
andrej@1736: 
Edouard@592: class IEC_TIME(Structure):
Edouard@592:     """
Edouard@592:     Must be changed according to changes in iec_types.h
Edouard@592:     """
andrej@1737:     _fields_ = [("s", c_long),   # tv_sec
andrej@1737:                 ("ns", c_long)]  # tv_nsec
Edouard@592: 
andrej@1736: 
edouard@3813: def _t(t, u=lambda x: x.value, p=lambda t, x: t(x)):
andrej@1835:     return (t, u, p)
andrej@1736: 
andrej@1736: 
andrej@1835: def _ttime():
andrej@1835:     return (IEC_TIME,
edouard@3813:             lambda x: td(0, x.s, x.ns/1000.0),
andrej@1835:             lambda t, x: t(x.days * 24 * 3600 + x.seconds, x.microseconds*1000))
Edouard@592: 
andrej@1749: 
Edouard@592: SameEndianessTypeTranslator = {
edouard@3813:     "BOOL":       _t(c_uint8, lambda x: bool(x.value)),
andrej@1739:     "STEP":       _t(c_uint8),
andrej@1739:     "TRANSITION": _t(c_uint8),
andrej@1739:     "ACTION":     _t(c_uint8),
andrej@1739:     "SINT":       _t(c_int8),
andrej@1739:     "USINT":      _t(c_uint8),
andrej@1739:     "BYTE":       _t(c_uint8),
andrej@1739:     "STRING":     (IEC_STRING,
edouard@3886:                    lambda x: x.body[:x.len].decode(),
edouard@3823:                    lambda t, x: t(len(x), x.encode() if type(x)==str else x)),
andrej@1739:     "INT":        _t(c_int16),
andrej@1739:     "UINT":       _t(c_uint16),
andrej@1739:     "WORD":       _t(c_uint16),
andrej@1739:     "DINT":       _t(c_int32),
andrej@1739:     "UDINT":      _t(c_uint32),
andrej@1739:     "DWORD":      _t(c_uint32),
andrej@1739:     "LINT":       _t(c_int64),
andrej@1739:     "ULINT":      _t(c_uint64),
andrej@1739:     "LWORD":      _t(c_uint64),
andrej@1739:     "REAL":       _t(c_float),
andrej@1739:     "LREAL":      _t(c_double),
andrej@1739:     "TIME":       _ttime(),
andrej@1739:     "TOD":        _ttime(),
andrej@1739:     "DATE":       _ttime(),
andrej@1739:     "DT":         _ttime(),
Edouard@1433:     }
Edouard@592: 
Edouard@592: SwapedEndianessTypeTranslator = {
andrej@1733:     # TODO
Edouard@1433:     }
Edouard@592: 
andrej@1742: TypeTranslator = SameEndianessTypeTranslator
Edouard@1075: 
Edouard@592: # Construct debugger natively supported types
kinsamanka@3750: DebugTypesSize = dict([(key, sizeof(t)) for key, (t, p, u) in SameEndianessTypeTranslator.items() if t is not None])
Edouard@592: 
andrej@1736: 
Edouard@1433: def UnpackDebugBuffer(buff, indexes):
andrej@1758:     res = []
Edouard@1433:     buffoffset = 0
Edouard@1433:     buffsize = len(buff)
kinsamanka@3771:     buffptr = cast(cast(buff, c_char_p), c_void_p).value
Edouard@1433:     for iectype in indexes:
kinsamanka@3771:         c_type, unpack_func, _pack_func = TypeTranslator.get(iectype,
kinsamanka@3771:                                                              (None, None, None))
Edouard@3395: 
Edouard@3395:         cursor = c_void_p(buffptr + buffoffset)
Edouard@3395:         if iectype == "STRING":
Edouard@3395:             # strlen is stored in c_uint8 and sizeof(c_uint8) is 1
Edouard@3395:             # first check we can read size
Edouard@3395:             if (buffoffset + 1) <= buffsize:
Edouard@3395:                 size = 1 + cast(cursor,POINTER(c_type)).contents.len
Edouard@3395:             else:
Edouard@3395:                 return None
Edouard@3395:         else:
Edouard@3395:             size = sizeof(c_type)
Edouard@3395: 
Edouard@3395:         if c_type is not None and (buffoffset + size) <= buffsize:
edouard@3830:             ptr = cast(cursor, POINTER(c_type))
edouard@3830:             value = unpack_func(ptr.contents)
Edouard@3395:             buffoffset += size
Edouard@1433:             res.append(value)
Edouard@1075:         else:
Edouard@2741:             return None
Edouard@1433:     if buffoffset and buffoffset == buffsize:
Edouard@1075:         return res
Edouard@1075:     return None
edouard@3887: 
edouard@3887: def ValueToIECBytes(iectype, value):
edouard@3887:     if value is None:
edouard@3887:         return None
edouard@3887:     c_type, _unpack_func, pack_func = TypeTranslator[iectype]
edouard@3887:     return bytes(pack_func(c_type, value))