Ethernet header is corrupted when sending UDP data using Indy 10 - udp

The application sends UDP data to 192.168.178.24:
var
LoggerIP : String ;
Code_String : String ;
i : Integer ;
Errorpos : Integer ;
begin
LoggerIP := '192.168.178.24' ;
//LoggerIP := Edit1.Text + '.' + Edit2.Text + '.' + Edit3.Text + '.' + Edit4.Text ;
Showmessage (LoggerIP) ;
LoggerPort := 47333 ;
HelloString := 'Hello String' ;
Code_String := '0103262c00000000' +
'0000000000000099' +
'000400a555050000' +
'00289200046606b7' +
'36340380c058c3f4' +
'0cddff57d75df5d1' +
'fcf0600881b90003' +
'0f511ea522581746' +
'00000000' ;
// generate the 68 bytes to send
for i := 0 to 67 do
begin
val('$' + copy(Code_String, (i * 2) + 1 , 2), SendArray[i], Errorpos) ;
end ;
SetLength(send_data, sizeof(SendArray));
Move(SendArray, send_data[0], sizeof(SendArray)) ;
udp := TIdUDPClient.Create(nil);
try
udp.host := LoggerIP ;
udp.Port := loggerPort ;
//send message to Server
udp.SendBuffer (send_data) ;
finally
udp.free
end;
end;
This works as expected.
BUT, if the code:
//LoggerIP := Edit1.Text + '.' + Edit2.Text + '.' + Edit3.Text + '.' + Edit4.Text ;
is uncommented, so that the IP address may be selected, the Ethernet packet is corrupted (at least the MAC address - data is OK).
The image illustrates the Wireshark display.

Related

huobi signature always return "Signature not valid": Verification failure

Trying to access accounts I receive signature failure.
My signature is exactly the same as the reply in this link:
https://www.devglan.com/online-tools/hmac-sha256-online
(base_64)
I use this routine in freepascal for the calculation:
function getsignature(StringToSign , mykey:string):string;
var LHMAC: IHMAC;
begin
LHMAC := THashFactory.THMAC.CreateHMAC(THashFactory.TCrypto.CreateSHA2_256);
LHMAC.Key := TConverters.ConvertStringToBytes(MyKey, TEncoding.UTF8);
getsignature := TBase64.Default.Encode(LHMAC.ComputeString(StringToSign,
TEncoding.UTF8).GetBytes() );
end;
The total URL for the GET() is:
https://api.huobi.pro/v1/account/accounts?AccessKeyId=xxxxxxxx-xapikeyx-xxxxxxxxxx-xxxxx&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2021-04-27T12%3A55%3A07&Signature=nypzWyIf5f%xxxxxxxxsignatureresultxxxxxxxxxxx%3D
reply from server is:
{"status":"error","err-code":"api-signature-not-valid","err-msg":"Signature not valid: Verification failure [校验失败]","data":null}
n := chr($0A) ;
pre_signed_text := 'GET' + n + 'api.huobi.pro' + n + '/v1/account/accounts' + n
+ Ak + '&' + Sigmet + '&' + Sigver + '&' + Timestamp;
this is the correct text to sign. it works now.

SQL patindex equivalent in PostgreSQL

I am in need of Postgres equivalent of the SQL function patindex
There is no exact equivalent to SQL Server's PATINDEX function. You can use other string functions for your needs. Here is the docs: https://www.postgresql.org/docs/current/static/functions-string.html
But if you need exactly the same function, you can write a "wrapper" as shown below:
CREATE OR REPLACE FUNCTION "patindex"( "pattern" VARCHAR, "expression" VARCHAR ) RETURNS INT AS $BODY$
SELECT
COALESCE(
STRPOS(
$2
,(
SELECT
( REGEXP_MATCHES(
$2
,'(' || REPLACE( REPLACE( TRIM( $1, '%' ), '%', '.*?' ), '_', '.' ) || ')'
,'i'
) )[ 1 ]
LIMIT 1
)
)
,0
)
;
$BODY$ LANGUAGE 'sql' IMMUTABLE;
Example:
SELECT patindex( '%e_t%', 'Test String' );
2
SELECT patindex( '%S_r%', 'Test String' );
6
SELECT patindex( '%x%', 'Test String' );
0
PATINDEX and POSIX regular expressions are not fully compatible. For my purpose I finished with such version:
CREATE OR REPLACE FUNCTION _patexpr2regexp
(pattern TEXT) RETURNS TEXT
AS
$$
DECLARE
buffer TEXT = '';
matches TEXT[];
match_part TEXT;
pattern_part TEXT;
match_position INT;
BEGIN
FOR matches IN SELECT regexp_matches(pattern, '(_|\[%\]|%|.)', 'g')
LOOP
-- parsing
match_part := matches[1];
match_position := position(match_part IN pattern);
pattern_part := substring(pattern, 1, match_position + LENGTH(match_part) - 1);
pattern := substring(pattern, LENGTH(pattern_part) + 1);
-- replacements
IF match_part = '%'
THEN
-- lookaround regex pattern
pattern_part = replace(pattern_part, '%', '(?=.*)');
END IF;
IF match_part = '[%]'
THEN
-- % escape
pattern_part = replace(pattern_part, '[%]', '%');
END IF;
IF match_part = '_'
THEN
-- MSSQL _ means anysymbol (dot in regexp)
pattern_part = replace(pattern_part, '_', '.');
END IF;
IF match_part = '.'
THEN
-- actaul dot symbol should be escaped
pattern_part = replace(pattern_part, '.', '\.');
END IF;
buffer := buffer || pattern_part;
RAISE NOTICE 'matches: % -> % -> % -> % | %', matches, match_part, pattern_part, pattern, buffer;
END LOOP;
RAISE NOTICE 'result buffer: %', buffer;
RETURN buffer;
END;
$$ LANGUAGE plpgsql STRICT
IMMUTABLE
PARALLEL SAFE;
CREATE OR REPLACE FUNCTION "PATINDEX"
(pattern VARCHAR,
expression VARCHAR,
flags VARCHAR = 'i' -- default behaviour is case insensitive
) RETURNS INT
AS
$$
WITH cte AS (
SELECT (
REGEXP_MATCH(
expression,
_patexpr2regexp(pattern),
flags)
)[1] AS m
)
SELECT COALESCE(position(m IN expression), 0)
FROM cte;
$$ LANGUAGE sql STRICT
IMMUTABLE
PARALLEL SAFE;
-- checks
DO
$$
BEGIN
ASSERT "PATINDEX"('%.%', 'file.bat ') = 5;
ASSERT "PATINDEX"('%.%', 'file.bat.as1 ') = 5;
ASSERT "PATINDEX"('%.%', 'fileas') = 0;
ASSERT "PATINDEX"(NULL, 'abc') IS NULL;
ASSERT "PATINDEX"('abc', NULL) IS NULL;
ASSERT "PATINDEX"('abc', 'abc') = 1;
ASSERT "PATINDEX"('abc', 'cba abc') = 7;
-- TODO: not recognize properly
-- ASSERT "PATINDEX"( '%_1_%[0-9][%]', '123 21234%') = 5;
END;
$$;
[local]:5433 postgres#postgres=# select strpos('SQL Pattern Index','ern');
strpos
--------
9
(1 row)

Inno Setup ADO Connection for run sql query provides error

I managed [code] section of my installer in order to run a simple sql script (a select against an existing db/table).
Compiles fine, retrieve correctly sql machine and instance using the right password but whenever running the installer, at a moment the setup aborts providing message "Microsoft OLE DB Provider for SQL Server: Could not find store procedure 'ÿƥS'.
Of course none of those characters were defined in the sql script (SELECT ##SERVERNAME AS SERVERNAME, DB_NAME() AS [DB_NAME], CURRENT_USER AS [CURRENT_USER]).
Here is the [Code] section:
[Code]
const
//some constants definition
var
//some var definition
var
Page: TWizardPage;
// Used to generate error code by sql script errors
procedure ExitProcess(exitCode:integer);
external 'ExitProcess#kernel32.dll stdcall';
// enable/disable child text boxes & functions when text has been entered into Server textbox. Makes no sense to populate child items unless a value exists for server.
Procedure ServerOnChange (Sender: TObject);
begin
//code there
end;
// enable/disable user/pass text boxes depending on selected auth type. A user/pass is only required for SQL Auth
procedure AuthOnChange (Sender: TObject);
begin
//code there
end;
// Enable next button once a database name has been entered.
Procedure DatabaseOnChange (Sender: TObject);
//code there
end;
// Retrieve a list of databases accessible on the server with the credentials specified.
// This list is shown in the database dropdown list
procedure RetrieveDatabaseList(Sender: TObject);
var
ADOCommand: Variant;
ADORecordset: Variant;
ADOConnection: Variant;
begin
lstDatabase.Items.Clear;
try
// create the ADO connection object
ADOConnection := CreateOleObject('ADODB.Connection');
// build a connection string; for more information, search for ADO
// connection string on the Internet
ADOConnection.ConnectionString :=
'Provider=SQLOLEDB;' + // provider
'Data Source=' + txtServer.Text + ';' + // server name
'Application Name=' + '{#SetupSetting("AppName")}' + ' DB List;'
if chkWindowsAuth.Checked then
ADOConnection.ConnectionString := ADOConnection.ConnectionString +
'Integrated Security=SSPI;' // Windows Auth
else
ADOConnection.ConnectionString := ADOConnection.ConnectionString +
'User Id=' + txtUsername.Text + ';' + // user name
'Password=' + txtPassword.Text + ';'; // password
// open the connection by the assigned ConnectionString
ADOConnection.Open;
try
// create the ADO command object
ADOCommand := CreateOleObject('ADODB.Command');
// assign the currently opened connection to ADO command object
ADOCommand.ActiveConnection := ADOConnection;
// assign text of a command to be issued against a provider
ADOCommand.CommandText := 'SELECT name FROM master.dbo.sysdatabases WHERE HAS_DBACCESS(name) = 1 ORDER BY name';
// this property setting means, that you're going to execute the
// CommandText text command; it does the same, like if you would
// use only adCmdText flag in the Execute statement
ADOCommand.CommandType := adCmdText;
// this will execute the command and return dataset
ADORecordset := ADOCommand.Execute;
// get values from a dataset using 0 based indexed field access;
// notice, that you can't directly concatenate constant strings
// with Variant data values
while not ADORecordset.eof do
begin
lstDatabase.Items.Add(ADORecordset.Fields(0));
ADORecordset.MoveNext;
end ;
finally
ADOConnection.Close;
end;
except
MsgBox(GetExceptionMessage, mbError, MB_OK);
end;
end;
// Execute files specified in [files] section (hardcoded) against the user defined server.database
procedure DeploySQL();
var
Myscript: AnsiString;
ADOCommand: Variant;
ADOConnection: Variant;
begin
// extract script
ExtractTemporaryFile('script.sql');
try
// create the ADO connection object
ADOConnection := CreateOleObject('ADODB.Connection');
// build a connection string; for more information, search for ADO
// connection string on the Internet
ADOConnection.ConnectionString :=
'Provider=SQLOLEDB;' + // provider
'Data Source=' + txtServer.Text + ';' + // server name
'Initial Catalog=' + lstDatabase.Text + ';' + // server name
'Application Name=' + '{#SetupSetting("AppName")}' + ' Execute SQL;' ;
if chkWindowsAuth.Checked then
ADOConnection.ConnectionString := ADOConnection.ConnectionString +
'Integrated Security=SSPI;' // Windows Auth
else
ADOConnection.ConnectionString := ADOConnection.ConnectionString +
'User Id=' + txtUsername.Text + ';' + // user name
'Password=' + txtPassword.Text + ';'; // password
// open the connection by the assigned ConnectionString
ADOConnection.Open;
try
// create the ADO command object
ADOCommand := CreateOleObject('ADODB.Command');
// assign the currently opened connection to ADO command object
ADOCommand.ActiveConnection := ADOConnection;
// load a script from file into variable.
if(LoadStringFromFile(ExpandConstant('{app}\script.sql'), Myscript)) then
begin
// assign text of a command to be issued against a provider. Append all 3 because one of the install assembly strings will always be empty.
ADOCommand.CommandText := Myscript;
// this will execute the script; the adCmdText flag here means
// you're going to execute the CommandText text command, while
// the adExecuteNoRecords flag ensures no data row will be get
// from a provider, what should improve performance
ADOCommand.Execute(NULL, NULL, adCmdText or adExecuteNoRecords);
end
else
begin
MsgBox('Installation files missing.', mbError, MB_OK);
ExitProcess(7);
end ;
finally
ADOConnection.Close;
end;
except
MsgBox(GetExceptionMessage, mbError, MB_OK);
ExitProcess(5);
end;
end;
{ CustomForm_NextkButtonClick }
// try to connect to supplied db. Dont need to catch errors/close conn on error because a failed connection is never opened.
function CustomForm_NextButtonClick(Page: TWizardPage): Boolean;
var
ADOConnection: Variant;
begin
//try
// create the ADO connection object
ADOConnection := CreateOleObject('ADODB.Connection');
// build a connection string; for more information, search for ADO
// connection string on the Internet
ADOConnection.ConnectionString :=
'Provider=SQLOLEDB;' + // provider
'Data Source=' + txtServer.Text + ';' + // server name
'Initial Catalog=' + lstDatabase.Text + ';' + // server name
'Application Name=' + '{#SetupSetting("AppName")}' + ' Execute SQL;' ;
if chkWindowsAuth.Checked then
ADOConnection.ConnectionString := ADOConnection.ConnectionString +
'Integrated Security=SSPI;' // Windows Auth
else
ADOConnection.ConnectionString := ADOConnection.ConnectionString +
'User Id=' + txtUsername.Text + ';' + // user name
'Password=' + txtPassword.Text + ';'; // password
// open the connection by the assigned ConnectionString
ADOConnection.Open;
Result := True;
end;
{ CustomForm_CreatePage }
function CustomForm_CreatePage(PreviousPageId: Integer): Integer;
begin
Page := CreateCustomPage(
PreviousPageId,
ExpandConstant('{cm:CustomForm_Caption}'),
ExpandConstant('{cm:CustomForm_Description}')
);
{ lblServer }
lblServer := TLabel.Create(Page);
with lblServer do
begin
Parent := Page.Surface;
Caption := ExpandConstant('{cm:CustomForm_lblServer_Caption0}');
Left := ScaleX(24);
Top := ScaleY(32);
Width := ScaleX(68);
Height := ScaleY(13);
Enabled := True;
end;
{ txtServer }
txtServer := TEdit.Create(Page);
with txtServer do
begin
Parent := Page.Surface;
Left := ScaleX(112);
Top := ScaleY(32);
Width := ScaleX(273);
Height := ScaleY(21);
TabOrder := 1;
Enabled := True;
OnChange := #ServerOnChange;
end;
{ lblAuthType }
lblAuthType := TLabel.Create(Page);
with lblAuthType do
begin
Parent := Page.Surface;
Caption := ExpandConstant('{cm:CustomForm_lblAuthType_Caption0}');
Left := ScaleX(24);
Top := ScaleY(72);
Width := ScaleX(87);
Height := ScaleY(13);
Enabled := False;
end;
{ chkWindowsAuth }
chkWindowsAuth := TRadioButton.Create(Page);
with chkWindowsAuth do
begin
Parent := Page.Surface;
Caption := ExpandConstant('{cm:CustomForm_chkWindowsAuth_Caption0}');
Left := ScaleX(32);
Top := ScaleY(88);
Width := ScaleX(177);
Height := ScaleY(17);
Checked := True;
TabOrder := 2;
TabStop := True;
OnClick := #AuthOnChange;
Enabled := False;
end;
{ chkSQLAuth }
chkSQLAuth := TRadioButton.Create(Page);
with chkSQLAuth do
begin
Parent := Page.Surface;
Caption := ExpandConstant('{cm:CustomForm_chkSQLAuth_Caption0}');
Left := ScaleX(32);
Top := ScaleY(108);
Width := ScaleX(185);
Height := ScaleY(17);
TabOrder := 3;
OnClick := #AuthOnChange;
Enabled := False;
end;
{ lblUser }
lblUser := TLabel.Create(Page);
with lblUser do
begin
Parent := Page.Surface;
Caption := ExpandConstant('{cm:CustomForm_lblUser_Caption0}');
Left := ScaleX(56);
Top := ScaleY(128);
Width := ScaleX(58);
Height := ScaleY(13);
Enabled := False;
end;
{ lblPassword }
lblPassword := TLabel.Create(Page);
with lblPassword do
begin
Parent := Page.Surface;
Caption := ExpandConstant('{cm:CustomForm_lblPassword_Caption0}');
Left := ScaleX(56);
Top := ScaleY(152);
Width := ScaleX(53);
Height := ScaleY(13);
Enabled := False;
end;
{ txtUsername }
txtUsername := TEdit.Create(Page);
with txtUsername do
begin
Parent := Page.Surface;
Left := ScaleX(120);
Top := ScaleY(128);
Width := ScaleX(241);
Height := ScaleY(21);
Enabled := False;
TabOrder := 4;
end;
{ txtPassword }
txtPassword := TPasswordEdit.Create(Page);
with txtPassword do
begin
Parent := Page.Surface;
Left := ScaleX(120);
Top := ScaleY(152);
Width := ScaleX(241);
Height := ScaleY(21);
Enabled := False;
TabOrder := 5;
end;
{ lblDatabase }
lblDatabase := TLabel.Create(Page);
with lblDatabase do
begin
Parent := Page.Surface;
Caption := ExpandConstant('{cm:CustomForm_lblDatabase_Caption0}');
Left := ScaleX(56);
Top := ScaleY(192);
Width := ScaleX(53);
Height := ScaleY(13);
Enabled := False;
end;
{ lstDatabase }
lstDatabase := TComboBox.Create(Page);
with lstDatabase do
begin
Parent := Page.Surface;
Left := ScaleX(120);
Top := ScaleY(192);
Width := ScaleX(145);
Height := ScaleY(21);
Enabled := False;
TabOrder := 6;
OnDropDown:= #RetrieveDatabaseList;
OnChange:= #DatabaseOnChange;
end;
with Page do
begin
OnNextButtonClick := #CustomForm_NextButtonClick;
end;
Result := Page.ID;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
// set initial status of next button. Should be disabled when page is first loaded, but should be enabled if user clicked back.
if CurPageID = Page.ID then
WizardForm.NextButton.Enabled := bIsNextEnabled;
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
// The preinstall step seems like the best time to do the actual install. The problem is that this is not a traditional install. Nothing is copied to the users' pc
if CurStep = ssInstall then
DeploySQL;
end;
procedure InitializeWizard();
begin
bIsNextEnabled := False;
CustomForm_CreatePage(wpLicense);
end;
Any idea?
thanks
I got the solution!
Problem occurs in the if(LoadStringFromFile(ExpandConstant('{app}\script.sql'), Myscript)) statement because the sql file was not ANSI coded.
Everything gone fine by changing the coding.
thanks everybody!

when use teetree(TeeChart's one Component) build a imageshape,it's display with error

when add a lot of picture node to the teetree control,and set text offset to 30,then scroll to the end,the last line display picture only.
how should i do?
this is the result of the error:
procedure TForm1.FormCreate(Sender: TObject);
var i:Integer;
imgBox:TImageShape;
curLeft,curTop:Integer; //绘制完成文档视图后当前左上角坐标
begin
curLeft:=-100-15;
curTop:=0;
for i:=0 to 10 do
begin
imgBox := TImageShape.Create(Self);
imgBox.Width := 100;
imgBox.Height := 100;
curLeft := curLeft + 100 + 15 * 2;
if (curLeft + 100 + 15)>= Tree1.Width then
begin
curLeft := 15;
curTop := curTop + 100 + 15 * 2;
end;
imgBox.Left := curLeft;
imgBox.Top := curTop;
imgBox.Font.Style:=[fsBold];
imgBox.Font.Size:=16;
imgBox.Text.VertAlign:=vtaBottom;
imgBox.Text.VertOffset:=30;
imgBox.Text.Add('Node'+inttostr(i));
imgBox.ImageListIndex:=0;
imgBox.Tree:=Tree1;
end;
end;
I've added it to the public tracker here with a possible fix to be further investigated.

VHDL - init std_logic_vector array from HEX file

I have simple "RAM" implemented as:
type memory_array is array(31 downto 0) of std_logic_vector(7 downto 0);
signal ram : memory_array;
I would like to init it's content from HEX file. I wonder about reading the file like:
ram_init: process
file file_ptr : text;
variable line_text : string(1 to 14);
variable line_num : line;
variable lines_read : integer := 0;
variable char : character;
variable tmp_hexnum : string(1 to 2);
begin
file_open(file_ptr,"../RAM.HEX",READ_MODE);
while (not endfile(file_ptr)) loop
readline (file_ptr,line_num);
READ (line_num,line_text);
if (lines_read < 32) then
tmp_hexnum := line_text(10 to 11);
-- ram(lines_read) <= tmp_hexnum;
lines_read := lines_read + 1;
wait for 10 ns;
end if;
end loop;
file_close(file_ptr);
wait;
end process;
The problem is (if this code above would works, which I don't even know), how to convert the tmp_hexnum string to std_logic_vector.
Please have patience with me, VHDL beginner.
The first mistake is to use a process : if you attempt to synthesise the design, the process won't do anything until the design is built and running; which is far too late to read a file!
Instead, wrap the init code in a function, and use that to initialise the memory
signal ram : memory_array := my_ram_init(filename => "../RAM.HEX");
This will work in simulation, and many synthesis tools will infer a RAM and initialise it correctly. If you declared a constant instead of a signal, this would create a ROM instead of a RAM.
Anyway the function looks a bit like
function my_ram_init(filename : string) return memory_array is
variable temp : memory_array;
-- other variables
begin
file_open(...);
-- you have a good handle on the function body
file_close(...);
return temp;
end function;
leaving you with the original problem :
temp(lines_read) <= to_slv(tmp_hexnum);
writing the to_slv function. There ought to be a standard library of these, but for some reason there isn't a universally accepted one. So, here's a start...
function to_slv (tmp_hexnum : string) return std_logic_vector is
variable temp : std_logic_vector(7 downto 0);
variable digit : natural;
begin
for i in tmp_hexnum'range loop
case tmp_hexnum(i) is
when '0' to '9' =>
digit := Character'pos(tmp_hexnum(i)) - Character'pos('0');
when 'A' to 'F' =>
digit := Character'pos(tmp_hexnum(i)) - Character'pos('A') + 10;
when 'a' to 'f' =>
digit := Character'pos(tmp_hexnum(i)) - Character'pos('a') + 10;
when others => digit := 0;
end case;
temp(i*4+3 downto i*4) := std_logic_vector(to_unsigned(digit));
end loop;
return temp;
end function;
Converting a string of variable length to std_logic_vector with length as 4 *
length of string, can be done with the function below:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
...
-- Convert string to std_logic_vector, assuming characters in '0' to '9',
-- 'A' to 'F', or 'a' to 'f'.
function str_to_slv(str : string) return std_logic_vector is
alias str_norm : string(1 to str'length) is str;
variable char_v : character;
variable val_of_char_v : natural;
variable res_v : std_logic_vector(4 * str'length - 1 downto 0);
begin
for str_norm_idx in str_norm'range loop
char_v := str_norm(str_norm_idx);
case char_v is
when '0' to '9' => val_of_char_v := character'pos(char_v) - character'pos('0');
when 'A' to 'F' => val_of_char_v := character'pos(char_v) - character'pos('A') + 10;
when 'a' to 'f' => val_of_char_v := character'pos(char_v) - character'pos('a') + 10;
when others => report "str_to_slv: Invalid characters for convert" severity ERROR;
end case;
res_v(res_v'left - 4 * str_norm_idx + 4 downto res_v'left - 4 * str_norm_idx + 1) :=
std_logic_vector(to_unsigned(val_of_char_v, 4));
end loop;
return res_v;
end function;
Your (both) answers helped me a lot. But it seems not working.
function ram_init(filename : string) return memory_array is
variable temp : memory_array;
file file_ptr : text;
variable line_line : line;
variable line_text : string(1 to 14);
variable tmp_hexnum : string(1 to 2);
variable lines_read : integer := 0;
begin
file_open(file_ptr,filename,READ_MODE);
while (lines_read < 32 and not endfile(file_ptr)) loop
readline (file_ptr,line_line);
read (line_line,line_text);
tmp_hexnum := line_text(10 to 11);
temp(lines_read) := hex_to_bin(tmp_hexnum);
lines_read := lines_read + 1;
end loop;
file_close(file_ptr);
return temp;
end function;
signal ram : memory_array := ram_init(filename=>"../RAM.HEX");
If I set tmp_hexnum to e.g. "0A", it's OK, but reading from file do not fill the RAM.
Can you please check the file part for me, too?