unit NMRAnetBufferPools; // ****************************************************************************** // // * Copyright: // (c) Mustangpeak Software 2012. // // The contents of this file are subject to the GNU GPL v3 licence/ you maynot use // this file except in compliance with the License. You may obtain a copy of the // License at http://www.gnu.org/licenses/gpl.html // // * Revision History: // 2012-02-01: Created // 2012-10-07: Version 1.0 // // * Description: // // ****************************************************************************** uses NMRAnetAppDefines, NMRAnetDefinesShared, NMRAnetDefines; {$I Options.inc} {.$DEFINE TRACK_BUFFER_POOLS} {.$DEFINE TRACK_BUFFER_ALLOCATIONS} {.$DEFINE TRACK_BUFFER_OVERFLOWS} {.$DEFINE TRACK_BUFFER_MAX_COUNT} type TBaseBufferPool = record Pool: array[0..MAX_BASE_BUFFER_POOL-1] of TBaseBuffer; // Pool Array MaxCount: Byte; // Max Count of Pool Buffers used Count: Byte; // Number of Buffers currently used end; TDataBufferPool = record Pool: array[0..MAX_DATA_BUFFER_POOL-1] of TDataBuffer; // Pool Array MaxCount: Byte; // Max Count of Pool Buffers used Count: Byte; // Number of Buffers currently used end; TDatagramBufferPool = record Pool: array[0..MAX_DATAGRAM_BUFFER_POOL-1] of TDatagramBuffer; // Pool Array MaxCount: Byte; // Max Count of Pool Buffers used Count: Byte; // Number of Buffers currently used end; TStreamBufferPool = record Pool: array[0..MAX_STREAM_BUFFER_POOL-1] of TStreamBuffer; // Pool Array MaxCount: Byte; // Max Count of Pool Buffers used Count: Byte; // Number of Buffers currently used NextLocalStreamID: Byte; // Next number to use for a local steam ID (SID), automatically hanlded if you use NMRAnetBufferPools_GetNextStreamID or NMRAnetBufferPools_InitializeStreamBuffer end; TConfigMemBufferPool = record Pool: array[0..MAX_CONFIG_MEM_BUFFER_POOL-1] of TConfigMemBuffer; // Pool Array MaxCount: Byte; // Max Count of Pool Buffers used Count: Byte; // Number of Buffers currently used end; procedure NMRAnetBufferPools_Initialize; procedure NMRAnetBufferPools_InitializeBaseBuffer(Buffer: PBaseBuffer); procedure NMRAnetBufferPools_InitializeDatagramBuffer(Buffer: PDatagramBuffer); procedure NMRAnetBufferPools_InitializeStreamBuffer(Buffer: PStreamBuffer; AllocateStreamID: Boolean); procedure NMRAnetBufferPools_InitializeConfigMemBuffer(Buffer: PConfigMemBuffer); procedure NMRAnetBufferPools_InitializeDataBuffer(Buffer: PDataBuffer); function NMRAnetBufferPools_AllocateBaseBuffer(var Buffer: PBaseBuffer): Boolean; procedure NMRAnetBufferPools_ReleaseBaseBuffer(Buffer: PBaseBuffer); function NMRAnetBufferPools_AllocateDatagramBuffer(var Buffer: PDatagramBuffer; ForTransmit: Boolean): Boolean; procedure NMRAnetBufferPools_ReleaseDatagramBuffer(Buffer: PDatagramBuffer); function NMRAnetBufferPools_AllocateStreamBuffer(var Buffer: PStreamBuffer; ForTransmit: Boolean): Boolean; procedure NMRAnetBufferPools_ReleaseStreamBuffer(Buffer: PStreamBuffer); function NMRAnetBufferPools_GetNextStreamID: Byte; function NMRAnetBufferPools_AllocateConfigMemBuffer(var Buffer: PConfigMemBuffer): Boolean; procedure NMRAnetBufferPools_ReleaseConfigMemBuffer(Buffer: PConfigMemBuffer); function NMRAnetBufferPools_AllocateDataBuffer(var Buffer: PDataBuffer): Boolean; procedure NMRAnetBufferPools_ReleaseDataBuffer(Buffer: PDataBuffer); procedure NMRAnetBufferPools_100ms_TimeTick; {$IFDEF TRACK_BUFFER_POOLS} procedure NMRAnetBufferPools_Print; {$ENDIF} var BaseBufferPool: TBaseBufferPool; DatagramPool: TDatagramBufferPool; StreamPool: TStreamBufferPool; ConfigMemPool: TConfigMemBufferPool; DataPool: TDataBufferPool; implementation {$IFDEF TRACK_BUFFER_POOLS} procedure NMRAnetBufferPools_Print; var s1: string[32]; begin IntToStr(BaseBufferPool.MaxCount, s1); UART1_Write_Text('BaseBufferPool Max Count: '+s1+LF); IntToStr(BaseBufferPool.Count, s1); UART1_Write_Text('BaseBufferPool Count: '+s1+LF); IntToStr(DatagramPool.MaxCount, s1); UART1_Write_Text('DatagramPool Max Count: '+s1+LF); IntToStr(DatagramPool.Count, s1); UART1_Write_Text('DatagramPool Count: '+s1+LF); end; {$ENDIF} // ***************************************************************************** // // procedure NMRAnetBufferPools_100ms_TimeTick; // // Parameters: // None // Returns: // None // Description: // Updates internal flags to track for various timeout conditions mainly for the bus. // // WARNING: Application must make sure that the Datagram Array is not // modified in an interrupt when calling this function...... Disable the CAN for // the time this takes to run. // // ***************************************************************************** procedure NMRAnetBufferPools_100ms_TimeTick; var DatagramBuffer: PDatagramBuffer; i: Integer; begin for i := 0 to DatagramPool.Count - 1 do begin if DatagramPool.Pool[i].State and CBS_ALLOCATED = CBS_ALLOCATED then begin if DatagramPool.Pool[i].iWatchdog < DATAGRAM_WATCHDOG_MAX then Inc(DatagramPool.Pool[i].iWatchdog); end; end; for i := 0 to StreamPool.Count - 1 do begin if StreamPool.Pool[i].State and CBS_ALLOCATED = CBS_ALLOCATED then begin if StreamPool.Pool[i].iWatchdog < STREAM_WATCHDOG_MAX then Inc(StreamPool.Pool[i].iWatchdog); end; end; end; // ***************************************************************************** // procedure NMRAnetBufferPools_InitializeBaseBuffer; // // Parameters: // // Result: // // Description: // ***************************************************************************** procedure NMRAnetBufferPools_InitializeBaseBuffer(Buffer: PBaseBuffer); begin Buffer^.State := 0; Buffer^.Alias := 0; Buffer^.Next := nil; Buffer^.mCode := 0; Buffer^.Tag := 0; Buffer^.StateMachine := 0; end; // ***************************************************************************** // procedure NMRAnetBufferPools_InitializeDatagramBuffer; // // Parameters: // // Result: // // Description: // ***************************************************************************** procedure NMRAnetBufferPools_InitializeDatagramBuffer(Buffer: PDatagramBuffer); var j: Integer; begin if Buffer <> nil then begin Buffer^.State := 0; Buffer^.Alias := 0; Buffer^.Next := 0; Buffer^.mCode := 0; Buffer^.StateMachine := 0; Buffer^.Tag := 0; Buffer^.iByteCount := 0; Buffer^.iWatchdog := 0; Buffer^.ErrorCode.Count := 1; // Assume only the MTI Buffer^.ErrorCode.SubType[0] := 0; Buffer^.ErrorCode.SubType[1] := 0; Buffer^.iRetransmit := 0; for j := 0 to MAX_DATAGRAM_LEN-1 do Buffer^.DataBytes[j] := 0; end end; // ***************************************************************************** // procedure NMRAnetBufferPools_InitializeStreamBuffer; // // Parameters: // // Result: // // Description: // ***************************************************************************** procedure NMRAnetBufferPools_InitializeStreamBuffer(Buffer: PStreamBuffer; AllocateStreamID: Boolean); var j: Integer; begin if Buffer <> nil then begin Buffer^.State := 0; Buffer^.Alias := 0; Buffer^.Next := 0; Buffer^.mCode := 0; Buffer^.StateMachine := 0; Buffer^.Tag := 0; Buffer^.TotalTransferCount := 0; Buffer^.iByteCount := 0; Buffer^.NegotiatedTransferSize := 0; for j := 0 to MAX_STREAM_LEN-1 do // Is this really needed? Will be slow if buffer is big Buffer^.DataBytes[j] := 0; if AllocateStreamID then Buffer^.LocalStreamID := NMRAnetBufferPools_GetNextStreamID else Buffer^.LocalStreamID := 0; // Unique ID defined by the Local Node that identifies the Stream Conversation Buffer^.Content.TypeIncluded := False; // True if the stream contained defined content and the rest of this record will be filled in when the stream is returned for j := 0 to MAX_STREAM_TYPE_CONTENT - 1 do Buffer^.Content.ContentType[j] := 0; Buffer^.InitiateFlags := 0; Buffer^.InitiateAdditionalFlags := 0; // See Stream Flags (SF_xxx) and Stream Additional Flags (SAF_xxx) for bit values Buffer^.RemoteStreamID := 0; Buffer^.iWatchdog := 0; Buffer^.iRetransmit := 0; end; end; // ***************************************************************************** // procedure NMRAnetBufferPools_InitializeConfigMemBuffer; // // Parameters: // // Result: // // Description: // ***************************************************************************** procedure NMRAnetBufferPools_InitializeConfigMemBuffer(Buffer: PConfigMemBuffer); var i: Integer; begin Buffer^.State := 0; Buffer^.Alias := 0; Buffer^.Next := 0; Buffer^.StateMachine := 0; Buffer^.Action := 0; Buffer^.AddressSpace := 0; Buffer^.Address := 0; Buffer^.DataCount := 0; Buffer^.DataOffset := 0; Buffer^.Stream := nil; for i := 0 to MAX_CONFIG_MEM_DATA - 1 do Buffer^.DataBytes[i] := 0; Buffer^.AckFlags := DATAGRAM_OK_ACK_REPLY_PENDING; // The Write call is no longer blocked until the write is complete so tell the caller to wait until we tell you the write is complete Buffer^.ErrorCode := CONFIG_MEM_RESULT_OK; Buffer^.ErrorString := ''; end; procedure NMRAnetBufferPools_InitializeDataBuffer(Buffer: PDataBuffer); var i: Integer; begin Buffer^.State := 0; Buffer^.Alias := 0; Buffer^.Next := nil; Buffer^.mCode := 0; Buffer^.StateMachine := 0; Buffer^.Tag := 0; Buffer^.Bytecount := 0; for i := 0 to CAN_DATA_LEN - 1 do Buffer^.Bytes[i] := 0; end; // ***************************************************************************** // procedure NMRAnetBufferPools_Initialize; // // Parameters: // // Result: // // Description: // ***************************************************************************** procedure NMRAnetBufferPools_Initialize; var i: Integer; begin for i := 0 to MAX_BASE_BUFFER_POOL - 1 do NMRAnetBufferPools_InitializeBaseBuffer(@BaseBufferPool.Pool[i]); BaseBufferPool.Count := 0; BaseBufferPool.MaxCount := 0; for i := 0 to MAX_DATAGRAM_BUFFER_POOL - 1 do NMRAnetBufferPools_InitializeDatagramBuffer(@DatagramPool.Pool[i]); DatagramPool.Count := 0; DatagramPool.MaxCount := 0; for i := 0 to MAX_CONFIG_MEM_BUFFER_POOL - 1 do NMRAnetBufferPools_InitializeConfigMemBuffer(@ConfigMemPool.Pool[i]); ConfigMemPool.Count := 0; ConfigMemPool.MaxCount := 0; for i := 0 to MAX_DATA_BUFFER_POOL - 1 do NMRAnetBufferPools_InitializeDataBuffer(@DataPool.Pool[i]); DataPool.Count := 0; DataPool.MaxCount := 0; for i := 0 to MAX_STREAM_BUFFER_POOL - 1 do NMRAnetBufferPools_InitializeStreamBuffer(@StreamPool.Pool[i], False); StreamPool.Count := 0; StreamPool.MaxCount := 0; end; // ***************************************************************************** // procedure NMRAnetBufferPools_AllocateBaseBuffer; // // Parameters: // // Result: // // Description: // ***************************************************************************** function NMRAnetBufferPools_AllocateBaseBuffer(var Buffer: PBaseBuffer): Boolean; var i: Integer; begin Result := False; for i := 0 to MAX_BASE_BUFFER_POOL - 1 do begin if BaseBufferPool.Pool[i].State = 0 then begin Buffer := @BaseBufferPool.Pool[i]; {$IFDEF TRACK_BUFFER_ALLOCATIONS} UART1_Write_Text('BB_Alloc: '); WordToHex(Buffer, s1); UART1_Write_Text('$'+s1+LF);{$ENDIF} NMRAnetBufferPools_InitializeBaseBuffer(Buffer); Buffer^.State := CBS_ALLOCATED; Inc(BaseBufferPool.Count); if BaseBufferPool.Count >= BaseBufferPool.MaxCount then BaseBufferPool.MaxCount := BaseBufferPool.Count; Result := True; {$IFDEF TRACK_BUFFER_MAX_COUNT}UART1_Write_Text('BB MaxCount: '); ByteToStr(BaseBufferPool.MaxCount, s1); UART1_Write_Text(s1+LF);{$ENDIF} Break end end; {$IFDEF TRACK_BUFFER_OVERFLOWS} if not Result then begin UART1_Write_Text('BaseAllocateFail: ' + LF);{NMRAnetBufferPools_Print;} end {$ENDIF} end; // ***************************************************************************** // procedure NMRAnetBufferPools_ReleaseBaseBuffer; // // Parameters: // // Result: // // Description: // ***************************************************************************** procedure NMRAnetBufferPools_ReleaseBaseBuffer(Buffer: PBaseBuffer); begin if Buffer <> nil then begin {$IFDEF TRACK_BUFFER_ALLOCATIONS}UART1_Write_Text('BB_Free: '); WordToHex(Buffer, s1); UART1_Write_Text('$'+s1+LF);{$ENDIF} Buffer^.State := 0; Dec(BaseBufferPool.Count); end; end; // ***************************************************************************** // procedure NMRAnetBufferPools_AllocateDatagramBuffer; // // Parameters: // // Result: // // Description: // ***************************************************************************** function NMRAnetBufferPools_AllocateDatagramBuffer(var Buffer: PDatagramBuffer; ForTransmit: Boolean): Boolean; var i: Integer; begin Result := False; for i := 0 to MAX_DATAGRAM_BUFFER_POOL - 1 do begin if DatagramPool.Pool[i].State = 0 then begin Buffer := @DatagramPool.Pool[i]; {$IFDEF TRACK_BUFFER_ALLOCATIONS}UART1_Write_Text('DG_Alloc: '); WordToHex(Buffer, s1); UART1_Write_Text('$'+s1+LF);{$ENDIF} NMRAnetBufferPools_InitializeDatagramBuffer(Buffer); Buffer^.State := CBS_ALLOCATED; if ForTransmit then Buffer^.State := Buffer^.State or CBS_OUTGOING; Inc(DatagramPool.Count); if DatagramPool.Count >= DatagramPool.MaxCount then DatagramPool.MaxCount := DatagramPool.Count; {$IFDEF TRACK_BUFFER_MAX_COUNT}UART1_Write_Text('DG MaxCount: '); ByteToStr(DatagramPool.MaxCount, s1); UART1_Write_Text(s1+LF); {$ENDIF} Result := True; Break end end; {$IFDEF TRACK_BUFFER_OVERFLOWS}if not Result then begin UART1_Write_Text('DatagramAllocateFail: ' + LF); {NMRAnetBufferPools_Print;} end{$ENDIF} end; // ***************************************************************************** // procedure NMRAnetBufferPools_ReleaseDatagramBuffer; // // Parameters: // // Result: // // Description: // ***************************************************************************** procedure NMRAnetBufferPools_ReleaseDatagramBuffer(Buffer: PDatagramBuffer); begin if Buffer <> nil then begin {$IFDEF TRACK_BUFFER_ALLOCATIONS}UART1_Write_Text('DG_Free: '); WordToHex(Buffer, s1); UART1_Write_Text('$'+s1+LF);{$ENDIF} Buffer^.State := 0; Dec(DatagramPool.Count); end; end; // ***************************************************************************** // procedure NMRAnetBufferPools_AllocateStreamBuffer; // // Parameters: // // Result: // // Description: // ***************************************************************************** function NMRAnetBufferPools_AllocateStreamBuffer(var Buffer: PStreamBuffer; ForTransmit: Boolean): Boolean; var i: Integer; begin Result := False; for i := 0 to MAX_STREAM_BUFFER_POOL - 1 do begin if StreamPool.Pool[i].State = 0 then begin Buffer := @StreamPool.Pool[i]; {$IFDEF TRACK_BUFFER_ALLOCATIONS}UART1_Write_Text('Stream_Alloc: '); WordToHex(Buffer, s1); UART1_Write_Text('$'+s1+LF);{$ENDIF} NMRAnetBufferPools_InitializeStreamBuffer(Buffer, True); Buffer^.State := CBS_ALLOCATED; if ForTransmit then Buffer^.State := Buffer^.State or CBS_OUTGOING; Inc(StreamPool.Count); if StreamPool.Count >= StreamPool.MaxCount then StreamPool.MaxCount := StreamPool.Count; {$IFDEF TRACK_BUFFER_MAX_COUNT}UART1_Write_Text('Stream MaxCount: '); ByteToStr(StreamPool.MaxCount, s1); UART1_Write_Text(s1+LF); {$ENDIF} Result := True; Break end end; {$IFDEF TRACK_BUFFER_OVERFLOWS}if not Result then begin UART1_Write_Text('StreamAllocateFail: ' + LF); {NMRAnetBufferPools_Print;} end{$ENDIF} end; // ***************************************************************************** // procedure NMRAnetBufferPools_ReleaseStreamBuffer; // // Parameters: // // Result: // // Description: // ***************************************************************************** procedure NMRAnetBufferPools_ReleaseStreamBuffer(Buffer: PStreamBuffer); begin if Buffer <> nil then begin {$IFDEF TRACK_BUFFER_ALLOCATIONS}UART1_Write_Text('Stream_Free: '); WordToHex(Buffer, s1); UART1_Write_Text('$'+s1+LF);{$ENDIF} Buffer^.State := 0; Dec(StreamPool.Count); end; end; // ***************************************************************************** // procedure NMRAnetBufferPools_GetNextStreamID; // // Parameters: // // Result: // // Description: // ***************************************************************************** function NMRAnetBufferPools_GetNextStreamID: Byte; begin Result := StreamPool.NextLocalStreamID; Inc(StreamPool.NextLocalStreamID); end; // ***************************************************************************** // procedure NMRAnetBufferPools_AllocateConfigMemBuffer; // // Parameters: // // Result: // // Description: // ***************************************************************************** function NMRAnetBufferPools_AllocateConfigMemBuffer(var Buffer: PConfigMemBuffer): Boolean; var i: Integer; begin Result := False; for i := 0 to MAX_CONFIG_MEM_BUFFER_POOL - 1 do begin if ConfigMemPool.Pool[i].State = 0 then begin Buffer := @ConfigMemPool.Pool[i]; {$IFDEF TRACK_BUFFER_ALLOCATIONS} UART1_Write_Text('CMB_Alloc: '); WordToHex(Buffer, s1); UART1_Write_Text('$'+s1+LF);{$ENDIF} NMRAnetBufferPools_InitializeConfigMemBuffer(Buffer); Buffer^.State := CBS_ALLOCATED; Inc(ConfigMemPool.Count); if ConfigMemPool.Count >= ConfigMemPool.MaxCount then ConfigMemPool.MaxCount := ConfigMemPool.Count; Result := True; {$IFDEF TRACK_BUFFER_MAX_COUNT}UART1_Write_Text('CMB MaxCount: '); ByteToStr(ConfigMemPool.MaxCount, s1); UART1_Write_Text(s1+LF);{$ENDIF} Break end end; {$IFDEF TRACK_BUFFER_OVERFLOWS} if not Result then begin UART1_Write_Text('ConfigMemAllocateFail: ' + LF);{NMRAnetBufferPools_Print;} end {$ENDIF} end; // ***************************************************************************** // procedure NMRAnetBufferPools_ReleaseConfigMemBuffer; // // Parameters: // // Result: // // Description: // ***************************************************************************** procedure NMRAnetBufferPools_ReleaseConfigMemBuffer(Buffer: PConfigMemBuffer); begin if Buffer <> nil then begin {$IFDEF TRACK_BUFFER_ALLOCATIONS}UART1_Write_Text('CMB_Free: '); WordToHex(Buffer, s1); UART1_Write_Text('$'+s1+LF);{$ENDIF} Buffer^.State := 0; Dec(ConfigMemPool.Count); end; end; // ***************************************************************************** // procedure NMRAnetBufferPools_AllocateDataBuffer; // // Parameters: // // Result: // // Description: // ***************************************************************************** function NMRAnetBufferPools_AllocateDataBuffer(var Buffer: PDataBuffer): Boolean; var i: Integer; begin Result := False; for i := 0 to MAX_DATA_BUFFER_POOL - 1 do begin if DataPool.Pool[i].State = 0 then begin Buffer := @DataPool.Pool[i]; {$IFDEF TRACK_BUFFER_ALLOCATIONS} UART1_Write_Text('DB_Alloc: '); WordToHex(Buffer, s1); UART1_Write_Text('$'+s1+LF);{$ENDIF} NMRAnetBufferPools_InitializeDataBuffer(Buffer); Buffer^.State := CBS_ALLOCATED; Inc(DataPool.Count); if DataPool.Count >= DataPool.MaxCount then DataPool.MaxCount := DataPool.Count; Result := True; {$IFDEF TRACK_BUFFER_MAX_COUNT}UART1_Write_Text('DB MaxCount: '); ByteToStr(DataPool.MaxCount, s1); UART1_Write_Text(s1+LF);{$ENDIF} Break end end; {$IFDEF TRACK_BUFFER_OVERFLOWS} if not Result then begin UART1_Write_Text('ConfigMemAllocateFail: ' + LF);{NMRAnetBufferPools_Print;} end {$ENDIF} end; // ***************************************************************************** // procedure NMRAnetBufferPools_ReleaseDataBuffer; // // Parameters: // // Result: // // Description: // ***************************************************************************** procedure NMRAnetBufferPools_ReleaseDataBuffer(Buffer: PDataBuffer); begin if Buffer <> nil then begin {$IFDEF TRACK_BUFFER_ALLOCATIONS}UART1_Write_Text('DB_Free: '); WordToHex(Buffer, s1); UART1_Write_Text('$'+s1+LF);{$ENDIF} Buffer^.State := 0; Dec(DataPool.Count); end; end; end.