Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How to pass and receive member data from Micros 3700 POS to C# Program thru Event rxmsg 1

Status
Not open for further replies.

manelandrea

Programmer
Jul 10, 2017
34
PH
Hi I'm new to Micros ISL and been going through some research on how can I integrate a C# WPF project to Micros 3700 SIM ISL. I read that rxmsg is executed when a response is received from the third-party system interfaced to the 3700 but I'm not really sure how it works since the documentation I am reading doesn't show how to. Anyone can teach me how should it be integrated? A sample c# program integration with ISL is greatly appreciated. Thank you so much!!!
 
For more detail info, here is the PDF:
RXMSG involves network communication. The message format that is sent is:

Code:
SOH ID STX FS Application_Sequence Application_Data ETX Checksum EOT

These are all specific constants that it uses to mark the data. Here are the constants in my C# class that defines the message format:

Code:
[COLOR=#0000FF]public[/color] [COLOR=#0000FF]const[/color] [COLOR=#0000FF]char[/color] StartOfHeader = [COLOR=#A31515]'\x001'[/color];
[COLOR=#0000FF]public[/color] [COLOR=#0000FF]const[/color] [COLOR=#0000FF]char[/color] StartOfText = [COLOR=#A31515]'\x002'[/color];
[COLOR=#0000FF]public[/color] [COLOR=#0000FF]const[/color] [COLOR=#0000FF]char[/color] EndOfText = [COLOR=#A31515]'\x003'[/color];
[COLOR=#0000FF]public[/color] [COLOR=#0000FF]const[/color] [COLOR=#0000FF]char[/color] EndOfTransmission = [COLOR=#A31515]'\x004'[/color];
[COLOR=#0000FF]public[/color] [COLOR=#0000FF]const[/color] [COLOR=#0000FF]char[/color] FieldSeparator = [COLOR=#A31515]'\x1C'[/color];

So for example, if I do this in my SIM file, from interface #2, from workstation #99, with my number of ID digits set to 9, and interface name ZOOM...

Note: ID is fixed width; it is always 16 bytes for the name of the interface and then either 2 or 9 for the interface number, based on the configuration in pos config.

Code:
EVENT INQ : 1
    TXMSG "GET_CHECKS"
    WAITFORRXMSG
ENDEVENT

.. the string will look like:

Code:
(SOH)000000099ZOOM            (STX)(FS)07 GET_CHECKS(ETX)081F(EOT)

So you will need to build something to parse that. You send data back in the same format. I would read the PDF I linked and then if you have specific questions ask them; I don't think too many people are going to post complete, working interface examples.
 
Thank you Moregelen!

So I created a c# based tcp/ip program that will wait for the micros sim message:

server_wwvdmw.png


But it just kept on waiting for the client to send the message. I'm pretty sure I am missing on something here, I'm just not sure what to add:

Code:
   public static void Main()
        {
            try
            {
                
                IPAddress ipAd = IPAddress.Parse("10.0.1.70");

                /* Initializes the Listener */
                TcpListener myList = new TcpListener(ipAd, 5009);

                /* Start Listeneting at the specified port */
                myList.Start();
               
                Console.WriteLine("The server is running at port 5009...");
                Console.WriteLine("The local End point is  :" + myList.LocalEndpoint);
                Console.WriteLine("Waiting for a connection.....");

               Socket s = myList.AcceptSocket();
              //  TcpClient tc = myList.AcceptTcpClient();
                Console.WriteLine("Connection accepted from " + s.RemoteEndPoint);

                byte[] b = new byte[100];
                int k = s.Receive(b);
                Console.WriteLine("Received...");
                for (int i = 0; i < k; i++)
                    Console.Write(Convert.ToChar(b[i]));

                ASCIIEncoding asen = new ASCIIEncoding();
                s.Send(asen.GetBytes("The string was recieved by the server."));
                Console.WriteLine("\nSent Acknowledgement");
                /* clean up */
                s.Close();
                myList.Stop();



            }
            catch (Exception e)
            {
                Console.WriteLine("Error..... " + e.StackTrace);
            }

            Console.ReadLine();
        }


Here is my ISL CODE:

Code:
var phone_num : N7 //Global variable, keep phone number around.

event inq : 4 //Use Inquiry key #1 to get guest info.
	var cust_name : A32
	var addr1 : A32
	var addr2 : A32
	var addr3 : A32
	var special_instructions : A32

	window 7, 50, "Customer Info"
	display 2,2, "Phone Number:"
	displayinput 2, 18, phone_num{:###-####}, "Enter phone number"
	display 3,2, "Customer name:"
	displayinput 3,18,cust_name, "Enter customer's name"
	display 4,2, "Address Line 1:"
	displayinput 4,18,addr1, "Enter address"
	display 5,2, "Address Line 2:"
	displayinput 5,18,addr2, "Enter address"
	display 6,2, "Address Line 3:"
	displayinput 6,18,addr3, "Enter address"
	display 7,2, "Instructions:"
	displayinput 7,18,special_instructions, "Enter instructions"
	windowinput
	
	infomessage cust_name

	txmsg phone_num, cust_name, addr1, addr2,addr3,special_instructions
						//send information 
						//a third party system

		
	waitforrxmsg


endevent


Here is the output of my ISL code:
isl_bxrzpc.png


What am I missing here? and is it right that I'm going to define the port on the interface?
interface_vaktyd.png


Greatly appreciate your help!
 
A few things.

Your inquiry is #4, but your comment says #1. I went ahead and changed that to 1.

You should use 127.0.0.1 in POS Config instead of the computer name if the service is going to be running on the same computer Micros is installed on; more reliable in the long term.

Your TCP client is also not quite setup correctly. Below are some code changes I've made that get you a visible message, with comments about why I made those changes. I also tweaked it a bit so that it will handle more than a one off connection to give you a basic idea how to do that. You should look into asyncronous operations though as what I've done is linear and will only allow one at a time. Keep in mind you HAVE to send your response back using the ISL format. Also you have to know the read will just hang even if there is no more data with the way that Micros wrote this - it does not close the stream, so you have to watch for the end of transmission control character. This example will at least let you look at what the data incoming looks like, and so you can see how you need to format the reply.


Code:
[COLOR=#0000FF]using[/color] System;
[COLOR=#0000FF]using[/color] System.Net;
[COLOR=#0000FF]using[/color] System.Net.Sockets;
[COLOR=#0000FF]using[/color] System.Text;
 
[[COLOR=#0000FF]assembly[/color]: [COLOR=#2B91AF]DefaultNamespace[/color]([COLOR=#A31515]"ScratchCode"[/color])]
[COLOR=#0000FF]namespace[/color] ScratchCode
{
    [COLOR=#0000FF]class[/color] [COLOR=#2B91AF]Program[/color]
    {
 
        [COLOR=#0000FF]static[/color] [COLOR=#0000FF]void[/color] Main([COLOR=#0000FF]string[/color][] args)
        {
            [COLOR=#0000FF]try[/color]
            {
 
                [COLOR=#008000]/* Initializes the Listener */[/color]
                [COLOR=#2B91AF]TcpListener[/color] myList = [COLOR=#0000FF]new[/color] [COLOR=#2B91AF]TcpListener[/color]([COLOR=#2B91AF]IPAddress[/color].Any, 5009); [COLOR=#008000]//change to IPAddress.Any so that it will accept connections from more than just the one IP[/color]
 
                [COLOR=#008000]/* Start Listeneting at the specified port */[/color]
                myList.Start();
 
                [COLOR=#2B91AF]Console[/color].WriteLine([COLOR=#A31515]"The server is running at port 5009..."[/color]);
                [COLOR=#2B91AF]Console[/color].WriteLine([COLOR=#A31515]"The local End point is  :"[/color] + myList.LocalEndpoint);
 
                [COLOR=#0000FF]char[/color] EndOfTransmission = [COLOR=#A31515]'\x004'[/color]; [COLOR=#008000]//need to keep reading until we hit this[/color]
 
                [COLOR=#0000FF]try[/color]
                {
                    [COLOR=#0000FF]while[/color] ([COLOR=#0000FF]true[/color]) [COLOR=#008000]//added loop so that program will keep listening for connnections rather than closing after receiving a single request[/color]
                    {
                        [COLOR=#2B91AF]Console[/color].WriteLine([COLOR=#A31515]"Waiting for a connection....."[/color]);
 
                        [COLOR=#008000]//Socket s = myList.AcceptSocket();[/color]
                        [COLOR=#2B91AF]TcpClient[/color] tc = myList.AcceptTcpClient(); [COLOR=#008000]//you had the right idea here - lets work with TcpClient's[/color]
 
                        [COLOR=#2B91AF]Console[/color].WriteLine([COLOR=#A31515]"Connection accepted from "[/color] + tc.Client.RemoteEndPoint); [COLOR=#008000]//you can still access the underlying socket[/color]
 
                        [COLOR=#0000FF]byte[/color][] b = [COLOR=#0000FF]new[/color] [COLOR=#0000FF]byte[/color][256]; [COLOR=#008000]//lets work with 256[/color]
                        [COLOR=#0000FF]string[/color] data = [COLOR=#0000FF]string[/color].Empty; [COLOR=#008000]//string to store incoming data[/color]
 
                        [COLOR=#2B91AF]NetworkStream[/color] s = tc.GetStream(); [COLOR=#008000]//get the stream for the socket[/color]
                        [COLOR=#2B91AF]Console[/color].WriteLine([COLOR=#A31515]"Got the stream"[/color]);
                        [COLOR=#0000FF]int[/color] k;
 
                        [COLOR=#0000FF]while[/color] (data.IndexOf(EndOfTransmission) == -1 && (k = s.Read(b, 0, b.Length)) != 0) [COLOR=#008000]//because Read will hang, make sure to check for EndOfTransmission first[/color]
                        { [COLOR=#008000]//Read returns how many bytes were read. Keep looping if there is more to read[/color]
                            data += [COLOR=#2B91AF]Encoding[/color].ASCII.GetString(b, 0, k);
                        }
 
                        [COLOR=#2B91AF]Console[/color].WriteLine([COLOR=#A31515]"Received..."[/color]);
                        [COLOR=#2B91AF]Console[/color].WriteLine(data); [COLOR=#008000]//no reason to loop each bytes, just write the string[/color]
 
                        [COLOR=#0000FF]byte[/color][] reply = [COLOR=#2B91AF]Encoding[/color].ASCII.GetBytes([COLOR=#A31515]"The string was recieved by the server."[/color]);
                        s.Write(reply, 0, reply.Length);
                        [COLOR=#2B91AF]Console[/color].WriteLine([COLOR=#A31515]"Sent Acknowledgement"[/color]);
 
                        s.Close();
 
                    }
                }
                [COLOR=#0000FF]catch[/color] ([COLOR=#2B91AF]Exception[/color] ex)
                {
                    [COLOR=#2B91AF]Console[/color].WriteLine(ex.Message);
                }
                [COLOR=#0000FF]finally[/color]
                {
                    [COLOR=#008000]/* clean up */[/color]
                    myList.Stop();
                }
            }
            [COLOR=#0000FF]catch[/color] ([COLOR=#2B91AF]Exception[/color] e)
            {
                [COLOR=#2B91AF]Console[/color].WriteLine([COLOR=#A31515]"Error..... "[/color] + e.StackTrace);
            }
 
            [COLOR=#2B91AF]Console[/color].ReadLine();
        }
    }
}
 
Thank you so much @moregelen! Great work! I can now send message from SIM to my server app. Just a question on sending back a reply, I saw one of your posts here in tektips:


From what I could understand, I should be creating another rxmsg comnmand that will receive the response from the server. I saw that you do that by

message.CreateReply("show_distance", Math.Abs(result.Distance));

May I know how should this be formatted? I mean, the one you send here is something like

byte[] reply = Encoding.ASCII.GetBytes("The string was received by the server.");
s.Write(reply, 0, reply.Length);

but of course the SIM will still prompt a no response message since the server app didn't send back which rxmsg command should it be passing the message to.

Thanks again for your help Moregelen!
 
You format it in the same format it came in when sending it back.

Basically a string like:

Code:
StartOfHeader + ID + StartOfText + FieldSeparator + ApplicationSequence + ApplicationDataString + EndOfText + CheckSum + EndOfTransmission


ID is defined as UWS# + InterfaceName, where interface name is a fixed width 16 character string and the width of UWS is defined in POS Configurator (either 2 or 9)

ApplicationSequence is defined as Sequence#+Re-transmission flag (the sequence number if fixed with 2 characters and goes from 01 to 99, and re-transmission flag is either R or a space).

ApplicationDataString is defined as CommandName + FieldSeparator + Data (each separate piece of data should have a FieldSeparator in between them).
The commandname is the ISL event, so event rxmsg : CommandName; this is how you control which event is called in the ISL when the reply comes in.


The checksum is obvious enough, fixed at 4 characters. Interestingly enough I've noticed that it doesn't actually matter. You can put 0000 there if you want and Micros won't care.
 
Hi Moregelen,

Thank you again for your quick response! :) May I know also if I return a response message, can I set the sequence number as any number from 01 to 99? and I set the UWS to 9 in my pos conifgurator, can I create a constant variable in my C# server app which has the value of 000000099? Thank you so much!
 
Hi Moregelen,

I read from the documentation that whatever sequence number is passed on the server, it will be the same sequence number passed as reply. Is it correct?

So I added a formatted code in my c# server file which goes like this:

Code:
var newstr = strFormat.StartOfHeader + "000000099prompt          " + strFormat.StartOfText + strFormat.FieldSeparator +  seq.Trim() + " success_reply" + strFormat.FieldSeparator + "hello" +
                                                            strFormat.FieldSeparator + strFormat.EndOfText + "0000" + strFormat.EndOfTransmission;
byte[] reply = Encoding.ASCII.GetBytes(newstr);
s.Write(reply, 0, reply.Length);

but still when I try to observe, before the c# debugger step on the reply code, the SIM already responded a no response message:
no_Response_ij6e8y.png


but whenever I checked on the log file, it shows that my response has been received:
LOG_FileSample_snaxoz.png


my isl code for the response is something like:
islCode_ejrfuj.png


and the 37000 log files shows the following errors:

log_ptxytm.png


and also there's this log file that has been generated which shows the error:
xmlLog_eshxii.png


Would you have any idea why is that just before C# sends back the reply to the client POS, the sim automatically respond the "No Response to Message" error? Thank you so much!
 
I can't actually see your screenshots (our firewall doesn't allow file sharing websites), but you need to be sending back the workstation ID in the return, so you can't hardcode it to 000000099. In fact, if your server is set to #9, by sending back 000000099 you are telling Micros you are replying to workstation 99 which doesn't exist. You can basically just send back the same ID and Application Sequence you received, and unless you need to worry about where the message is coming from because of configuration or something, you can even ignore it. I have a few interfaces that can be configured with specifics by workstation so those have to pay attention to that ID, but most interfaces I put together only look at that for logging purposes.
 
Also, if you're running your program and stepping in the debugger make sure to set your timeout high enough that by debugging you don't delay things so much that it times out. That would be a reason you're getting the No Response before it even steps to the attempt at a reply.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top