Buffer Management
Allocating Buffer Memory
Some objects, such as the sock. object or ser. object, rely on buffers for storing the data being sent and received. For example, each serial port of the ser. object has two buffers — RX and TX — while each socket of the sock. object has at least six different buffers.
By default, all buffers have no memory allocated for them, which basically means that they cannot store any data. For related objects to work, these buffers need to be given memory.
Memory is allocated in pages. Each page equals 256 bytes. There is a small overhead for each buffer — 17 bytes for 16-bit platforms and 33 bytes for 32-bit platforms — that are used for internal buffer houskeeping (variables, pointers, etc.). Therefore, if you have allocated 2 pages for a particular buffer, then this buffer's actual capacity will be 2 * (256 - 17) = 494 bytes.
Buffer memory allocation is a two-step process. First, you request certain number of pages for each port, socket, etc. that you plan to use. This is done through the methods of corresponding objects. For example, the ser.rxbuffrq method requests buffer memory for the RX buffer of one of the serial ports. Similar methods exist for all other buffers of all objects that require buffer memory. Note that actual memory allocation does not happen at this stage — only your "requests" are collected.
After all requests have been made, the actual memory allocation is performed by using the sys.buffalloc method. This allocates memory, as per previous requests, for all buffers of all objects. Here is an example:
'allocate memory for RX and TX buffers of serial port 0 and socket 0
'make requests
ser.num= 0
ser.rxbuffrq= 5
ser.txbuffrq= 5
sock.num=0
sock.rxbuffrq= 4
sock.txbuffrq= 4
'and now actual allocation
sys.buffalloc
Typically, buffer memory allocation is done in the on_sys_init event handler, but you don't have to do it this way. In fact, your application can reallocate buffer memory space according to changes in the operating mode or other conditions.
The sys.buffalloc method could take up to several hundred milliseconds to execute, so it makes sense to use it as little as possible. Hence, request all necessary buffer allocations first, then use sys.buffalloc once to finish the job.
Buffer (re)allocation for a specific object will only work if the corresponding object or part of the object to which this buffer belongs is idle. "Part" refers to a particular serial port of the ser. object or a particular socket of the sock. object, for example, to which the buffer you are trying to change belongs. "Idle" means different things for different objects: ser.enabled = 0 — NO for a serial port, sock.statesimple = 0 — PL_SSTS_CLOSED for a socket, etc.
Intelligent Memory Allocation Based on What's Available
Memory is not an infinite resource and you will not always get as much memory as you have requested. Methods such as ser.rxbuffrq actually return the amount of memory that can be allocated:
dim x as byte
x=ser.rxbuffrq(5) 'x could get less than 5, which means that you got less memory than you have asked for
Two properties of the sys. object were implemented to help you allocate memory intelligently, based on what is available:
- The sys.totalbuffpages read-only property tells you how many buffer pages are available in your system in total. This is defined by the amount of physical variable memory (RAM) available minus memory required to store your project's variables (so, as your project grows, the available buffer memory shrinks).
- The sys.freebuffpages read-only property tells you the amount of free (not yet allocated) buffer pages.
Here is an example in which we allocate memory equally between the TX and RX buffers of four serial ports and four sockets:
dim x,f as byte
x=sys.totalbuffpages/16 'will work correctly if we haven't allocated anything yet
for f=0 to 3
ser.num= f
ser.rxbuffrq(x)
ser.txbuffrq(x)
sock.num= f
sock.rxbuffrq(x)
sock.txbuffrq(x)
next f
In the above example, we do not check what individual buffer requests return because we have already calculated each buffer's size based on the total number of buffer pages available.