Parse router configuration output - c#

My router supports telnet sessions to configure my router, I want to make an application in c# that parses the console output into something useful.
edit: the lines are seperated with "\n\r" and there are no \t characters used, everything is spaced out
Example:
bridge configuration for "bridge" :
OBC : dest : Internal
Connection State: connected Retry: 10
Priority Tagging: Disabled
Port: OBC PortNr: 0 PortState: forwarding Interface: up
Multicast filter: disabled Dynamic VLAN : disabled
IGMP snooping : enabled
VLAN: Default VLAN: default Ingressfiltering: disabled Acceptvlanonly: disabled
VLAN: Priority: disabled IP Prec: disabled Priority: 0 Regeneration table: 0 1 2 3 4 5 6 7
RX bytes: 1978767922 frames: 21288686
TX bytes: 481256491 frames: 16224065 dropframes: 13671
ethport1 : dest : ethif1
Connection State: connected Retry: 10
Priority Tagging: NA (destination switch interface)
Port: ethport1 PortNr: 1 PortState: forwarding Interface: up
Multicast filter: disabled Dynamic VLAN : disabled
IGMP snooping : enabled
VLAN: Default VLAN: default Ingressfiltering: disabled Acceptvlanonly: disabled
VLAN: Priority: disabled IP Prec: disabled Priority: 0 Regeneration table: 0 1 2 3 4 5 6 7
RX bytes: 44045 frames: 0
TX bytes: 12618 frames: 0 dropframes: 0
Can somebody give me some hints?
My first thought was a regex, but I don't know how to do that on this scale.

"Into something useful" means to me that your first step is to create classes, structs, and enums that represent your data:
public class RouterEntry
{
public ConnectionState ConnectionState { get; }
public int Retry { get; }
...
public long BytesTX { get; }
}
Then, start thinking about how to parse the result strings. I would probably write a Deserialize(StringReader) method (or something along those lines) so that your object parses the data line by line.
You can also use string.Split with the SplitOptions overload to help you ignore any blank spaces.
So for example, if you use
Port: OBC PortNr: 0 PortState: forwarding Interface: up
as your input line, and
char[] delims = new char[] { ':', ' ' };
as your delimiters, then calling it like this
string[] tokens = line.Split(delims, StringSplitOptions.RemoveEmptyEntries);
would result in tokens containing
[Port, OBC, PortNr, 0, PortState, forwarding, Interface, up]
For the lines that have multiple "values" for a key (such as Regeneration table: 0 1 2 3... you'll just to take into account the fact that each of those values will be a separate string in the tokens array).
The key is that if you break your problem down one bit a time, it should become more manageable to solve.

Related

Why is the "€" character only printed before printer initialization and not after the initialization?

I have an Epson TM-T88VI printer and use the Microsoft.PointOfService.PosPrinter in C# for printing.
Using the following function i get a strange output printed:
public static void printerTestFunction2(string printerName)
{
PosExplorer explorer = new PosExplorer();
DeviceInfo di = explorer.GetDevice("PosPrinter", printerName);
PosPrinter printer = (PosPrinter)explorer.CreateInstance(di);
printer.Open();
printer.Claim(10000);
printer.DeviceEnabled = true;
printer.AsyncMode = false;
string init = System.Text.ASCIIEncoding.ASCII.GetString(new byte[] { 27, 64 });
string totalCut = System.Text.ASCIIEncoding.ASCII.GetString(new byte[] { 27, 105 });
string cmd = init + init + "A€A\nB€B\n" + init + "C€C\nD€D\n\n\n\n\n\n\n" + totalCut;
printer.PrintNormal(PrinterStation.Receipt, cmd);
}
The output is:
A€A
B€B
CFC
DFD
So the € symbol is printed as a strange "F" symbol (seems like the F is lower than the normal characters).
The paper is cut correctly.
I also have tested different constellations. It seems that the "€" sign is only printed before the first init command which is send to the printer after at least one row has been printed out. (I can send multiple init commands at the beginning - the € is printed. If i send the init after some chars have been printed, the "F" will appear instead of the "€").
If I restart my program, the "€" is again printed correctly, but if i send the init command it will be printed as "F" again.
What is the reason that the "€" symbol is only printed before the third init command?
Is there anything wrong with my code or do i miss a setting?
The reason why letters like F are printed is because the printer is in the initialized state, code page 437.
Look at the letters in the following material at 213 in decimal and 0xD5 in hexadecimal.
Page 0 [PC437: USA, Standard Europe]
Page 19 [PC858: Euro]
The POS for.NET service object internally manages code page settings according to the value of CharacterSet property.
If the application arbitrarily sends initialization commands to the printer, the service object's management information may be inconsistent and the printer may print incorrectly.
If you are using POS for.NET (including OPOS/JavaPOS), you should not use the initialization command (ESC#) or similar commands to change the mode or settings.
In that sense, instead of sending the paper cut also directly the ESC i({ 27, 105 }) command, call the CutPaper method or put the POSPrinter paper cut escape sequence (ESC|P) defined in UnifiedPOS in the print request string.

MongoDb - Get logs of the executed queries

I am using mongodb C# driver to perform all the operations on mongodb.
I want the logs like time taken to execute the operation, locks acquired, COLLSCAN/IXSCAN stage etc..
All I am getting now in my logs is the statements for creation and dropping of collections and indexes.
2019-08-26T14:44:57.444+0530 I INDEX [conn2] build index on: TestDb.System2 properties: { v: 2, unique: true, key: { description: 1 }, name: "description_1", ns: "TestDb.System2", background: true, sparse: false }
2019-08-26T14:44:57.444+0530 I INDEX [conn2] build index done. scanned 0 total records. 0 secs
2019-08-26T14:44:57.642+0530 I COMMAND [conn2] dropDatabase TestDb starting
2019-08-26T14:44:57.642+0530 I COMMAND [conn2] dropDatabase TestDb finished
How can I get the logs for the queries I am performing.
Also, I am aware of system.profile collection. I do not want to push the logs to this collection by enabling the profiling.
You have to enable the logs of all the writes
$ mongo
MongoDB shell version: 2.4.9
connecting to: testDb
> use myTestDb
switched to db myTestDb
> db.getProfilingLevel()
0
> db.setProfilingLevel(2)
{ "was" : 0, "slowms" : 1, "ok" : 1 }
> db.getProfilingLevel()
2
> db.system.profile.find().pretty()
Reference : https://docs.mongodb.com/manual/reference/method/db.setProfilingLevel/
db.setProfilingLevel(2)
This Query Logs all Operation

Read printer status after writing test string

I'm trying to write a string to a serial port, then send a command to tell the printer to return it's status in real time, if OK then send the next string.
I know how to create the form, create a serial port and write my string:
serialPort.Write("ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMN\n");
// send command to read status
// if status = 4, warn user & close port, if not...
// send next string
serialPort.Write("ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMN\n");
Where I'm having trouble is sending & receiving the real time status.
The command is:
Transmit real-time status
ASCII DLE EOTn [a]
Hex 10 04 n [a]
Decimal 16 4 n [a]
TM-T90, TM-T88IV, TM-U220 : 1 ≤ n ≤ 4, n = 7
TM-L90: 1 ≤ n ≤ 4, n = 8, a = 3 (when n = 8) (TM-L90 with Peeler)
1 ≤ n ≤ 4 (TM-L90 without Peeler)
n a Function
1 -- Transmit printer status
2 -- Transmit offline status
3 -- Transmit error status
4 -- Transmit roll paper sensor status
7 1 Transmit ink status A
2 Transmit ink status B
8 3 Transmit peeler status
All I care about is where n = 4 (Transmit roll paper sensor status)
If n returns 4, stop and close port with message to user that paper is low.
I will be using the same program for a 4 printers listed, like I said all I care about is if the status changes from 0 to 4.
I hope someone can help. Thank you.

Is it possible to get PC's # of physical USB ports?

I'm trying to get number of physical USB ports of PC for different Windows operating systems. To start with it seemed like an easy task but now I'm getting desperate.
Maybe this question is not even valid since I don't know how USB ports are treated on hardware level.
I thought using WMI(C) and ManagementObjectSearcher would be the right path to take and it returned right values... on certain operating systems. Or that's what I thought.
For example, I tried the following:
// >wmic path win32_usbhub get name
private const string UsbProperty = "Name";
private const string UsbPath = "Win32_USBHub";
private const string UsbPortName = "USB ROOT HUB";
...
// Get USB Ports
public IEnumerable<string> GetUsbPorts()
{
// All from Win32_USBHub where name contains USB ROOT HUB
return GetManagementObjectValues(UsbProperty, UsbPath).Where(name =>
CultureInfo.CurrentCulture.CompareInfo.IndexOf(
name, UsbPortName, CompareOptions.IgnoreCase) >= 0);
}
.
// Query
private static IEnumerable<string> GetManagementObjectValues(
string properties, string path, Func<object, string> formatter = null)
{
var values = new List<string>();
string query = string.Format("SELECT {0} FROM {1}", properties, path);
var search = new ManagementObjectSearcher(query);
try
{
foreach (ManagementObject item in search.Get())
{
string value = string.Empty;
foreach (string property in properties.Split(',')
.Select(prop => prop.Trim()))
{
if (item[property] == null)
continue;
if (value.Length > 0)
value += " ";
if (formatter != null)
value += formatter(item[properties]);
value += item[property].ToString();
}
values.Add(value.TrimEnd());
}
}
catch (Exception e)
{
if (e is ManagementException)
Logger.Warn(string.Format(
"Can't extract {0} properties of {1}", properties, path), e);
else
Logger.Error(e);
}
return values.Count >= 1 ? values : new List<string> { DefaultValue };
}
This seemed to get me the right amount on Windows8 but on WindowsXP it was totally off.
Next, I tried (for example) the following. I noticed that on Win8 I have USB<number> as ExternalReferenceDesignator but on WinXP, there's plain USB as InternalReferenceDesignator and external is empty.
For XP this seemed to work just fine but then again on Win8 amount of ports was six (6). Actual port count is 3 and with docking station station seven (7).
// >wmic path Win32_PortConnector get ExternalReferenceDesignator,InternalReferenceDesignator
private const string UsbPortName = "USB";
private const string PortProperties =
"ExternalReferenceDesignator, InternalReferenceDesignator";
private const string PortPath = #"Win32_PortConnector";
...
public IEnumerable<string> GetEthernetPorts()
{
// All where external includes USB or internal equals USB
return GetManagementObjectValues(PortProperties, PortPath).Where(name =>
CultureInfo.CurrentCulture.CompareInfo.IndexOf(
name, UsbPortName, CompareOptions.IgnoreCase) >= 0 ||
string.Compare(name, UsbPortName, StringComparison.OrdinalIgnoreCase) == 0);
}
So is it even possible or am I just looking from the wrong place?
And to answer my own question: No, it's not possible.
WMIC query results for Win32_USBController (or some related path) might seem right but you can't draw any conclusions from them. Information about connectors aren't stored on the baseboard or any other location either.
For example an old Dell Latitude D830 with Windows XP SP3 has three (3) physical connectors but WMIC and USBView.exe shows results below:
C:\>wmic path win32_usbcontroller get caption
Caption
Intel(R) ICH8 Family USB Universal Host Controller - 2834
Intel(R) ICH8 Family USB Universal Host Controller - 2835
Intel(R) ICH8 Family USB2 Enhanced Host Controller - 283A
Intel(R) ICH8 Family USB Universal Host Controller - 2830
Intel(R) ICH8 Family USB Universal Host Controller - 2831
Intel(R) ICH8 Family USB Universal Host Controller - 2832
Intel(R) ICH8 Family USB2 Enhanced Host Controller - 2836
I know it has been a while since the question was asked, but I just happened to be working on a USB port tree for a support app of some sort.
Initially, I tried to use Win32..., as much as it is not intended to be used as a source of information for the rebuilding of the device tree, the answer of this post explains some possibilities (Get List of connected USB Devices).
I played with it but I did not like it. UsbView by itself was also not an option (lack of skill in C ). Luckily I found NativeUsbLib. It provides you with a USB device tree, you just need to understand how to read it. Not a physical USB port This image shows a port that clearly states it is not possible to use it. In addition to that parameter, there is "Companion Hub Symbolic Link Name", in my experience, it has to be present on a valid USB port.
As for multiple controllers, and even multiple ports in one controller that satisfy my previous statement, there is an explanation. Multiple ports for same physical port, in my case, ports 1 and 13 are the same. If a device is 1.1 or 2.0 it will show under port 1, and if it supports 3.0 it will show up under port 13. And same goes for two controllers, they don't have 100% the same structure, but once you strip unnecessary data, and merge data (not necessarily all of it) that is left, the result will be a USB port tree. I can't guarantee all of the statements are true, but that is my current experience, and I might update this post. If not, feel free to message me if you have some questions. Btw. NativeUsbLib by default does not provide data for ports that don't have a device present (plugged in). To fix that, comment out lines in DeviceFactory that check if the device is present (line 35).
Hope this helps someone and sorry for my spelling, I am sure I messed up somewhere...

What Zebra QLn220 settings do I need to set (and to what value[s]) to get a setting to "stick"?

I am trying to programatically configure a Zebra QLn220 printer to set its "media.sense_mode" to either "bar" or "gap" (depending on what the user selects).
The reliability of these commands working, though, seems very low (sometimes it works, sometimes it doesn't).
To test the various possible commands, I used the Zebra Setup Utilities, with the PC plugged into the printer, of course.
I sent this command from the util:
! U1 setvar "media.sense_mode" "gap"
It worked; I know this, because testing it with:
! U1 getvar "media.sense_mode"
...showed me the expected/hoped for "gap" (it had been "bar" prior to sending the command above).
But trying to accomplish the same thing in code works for "bar" (almost always) but hardly ever for "gap"
Here's the code:
const string quote = "\"";
string advanceToBlackBar = string.Format("! U1 setvar {0}media.sense_mode{0} {0}bar{0}\r\n", quote);
string advanceToGap = string.Format("! U1 setvar {0}media.sense_mode{0} {0}gap{0}\r\n", quote);
. . .
if (radbtnBar.Checked)
{
PrintUtils.SendCommandToPrinter(advanceToBlackBar);
}
else if (radbtnGap.Checked)
{
PrintUtils.SendCommandToPrinter(advanceToGap);
}
So as you can see, the code is precisely the same except for "bar" vs. "gap"
Is it possible that the appended "\r\n" is causing a problem? It seems adding those were necessary or made the commands more reliable, but I'm open to anything at this point of frustration.
I always tested alternative commands for accomplishing the same thing, to see if they would be any more reliable, but neither of the other two alternatives worked, namely not this one:
! U1 setvar "ezpl.media_type" "web"
-nor this one:
{} {"media.sense_mode" "gap"}
...checking the val via getvar continued to show "bar" following the sending of those commands to the printer (after setting back to "bar" the value of "media.sense_mode" remains "bar" after sending these two commands).
Might it be that certain other printer settings need to be set for the printer to be more responsive to commands sent it? Not only is setting the commands programmatically unreliable, but even via the Zebra Setup Utility, it will sometimes "hourglass" for a LONG time before the command has been sent and returns - and other times it's quicker than Johnny Quick and Flash combined.
Looking through the voluminous output of this command:
! U1 getvar "allcv"
....the following are the most interesting/likely candidates. Which, if any, need to be changed, and to what values?
wlan.ip.dhcp.request_timeout : 2 , Choices: 2-30
wlan.ip.dhcp.session_interval : 10 , Choices: 0-60
. . .
wlan.ip.timeout.enable : on , Choices: on,off
wlan.ip.timeout.value : 300 , Choices: 1-3600
. . .
wlan.keep_alive.enable : on , Choices: on,off
wlan.keep_alive.timeout : 15 , Choices: 5-300
. . .
netmanage.avalanche.interval : 60000 , Choices: 0-4294967295
netmanage.avalanche.startup_update : off , Choices: on,off
netmanage.avalanche.interval_update : off , Choices: on,off
. . .
netmanage.avalanche.udp_timeout : 3000 , Choices: 0-4294967295
netmanage.avalanche.tcp_connection_timeout : 3000 , Choices: 0-4294967295
. . .
netmanage.avalanche.realtime_update_int : 300 , Choices: 0-4294967295
. . .
zpl.zpl_mode : zpl II , Choices: zpl II,zpl
. . .
internal_wired.ip.arp_interval : 0 , Choices: 0-30
. . .
internal_wired.ip.dhcp.requests_per_session : 2 , Choices: 1-10
internal_wired.ip.dhcp.request_timeout : 2 , Choices: 2-30
internal_wired.ip.dhcp.session_interval : 10 , Choices: 0-60
. . .
internal_wired.ip.timeout.enable : on , Choices: on,off
internal_wired.ip.timeout.value : 300 , Choices: 1-3600
. . .
internal_wired.ip.wins.permanent_source : off , Choices: on,off
. . .
interface.network.active.arp_interval : 0
. . .
interface.network.active.speed : 0
. . .
weblink.printer_reset_required : no
. . .
weblink.ip.conn1.retry_interval : 10 , Choices: 1-600
. . .
weblink.ip.conn1.maximum_simultaneous_connections : 10 , Choices: 1-100
. . .
weblink.ip.conn1.test.retry_interval : 900 , Choices: 1-1800
weblink.ip.conn1.num_connections : 0
. . .
capture.channel1.port : off , Choices: serial,usb,bt,parallel,off
capture.channel1.count : 0 , Choices: 0-4294967295
Anyone out there with a clue?
UPDATE
Here is the code that sends the commands:
public static bool SendCommandToPrinter(string cmd)
{
bool success; // init'd to false by default
try
{
using (SerialPort serialPort = new SerialPort())
{
serialPort.BaudRate = 19200;
serialPort.Handshake = Handshake.XOnXOff;
serialPort.Open();
serialPort.Write(cmd);
serialPort.Close(); // <= should be redundant within a using statement, but still getting "File 55" err...
}
success = true;
}
catch // may not need a try/catch block, as success defaults to false
{
success = false;
}
MessageBox.Show(success.ToString()); //TODO: Remove after testing
return success;
}
The SerialPort in question is from OpenNETCF.IO.Ports.SerialPort
NOTE: SerialPort.Write() returns void.
The command:
! U1 getvar "appl.name"
returns "V68.19.7Z" in the Zebra Setup Utility.
So does this mean my firmware is up-to-date (V68.19.7Z > v68.18.0Z), or does it mean since my "appl" is newer, I need to upgrade the firmware to V68.19.7Z? If I do need to update the firmware, how do I do that? Is it a matter of locating and downloading the latest firmware to my PC, then running its install app while the PC and Printer are connected via USB, or...???
UPDATE 2
From here, searching for QLn220, I see V68.18.0Z as the only firmware version available for download. So since I seem to have a newer version on my printer, I'm confused...why do they not offer what would seem to be the newer version (V68.19.7Z)?
UPDATE 3
If I click the "self-extracting archive" link at the page referenced above, I simply get a page with some generic but unactionable (so it seems) directions.
If I click the download link there, I get a page that says, "This webpage has a redirect loop"
UPDATE 4
It works after adding some debug strings; in the print code:
MessageBox.Show(success.ToString()); //TODO: Remove after testing
return success;
...and in the setting code:
if (radbtnBar.Checked)
{
MessageBox.Show(advanceToBlackBar);
PrintUtils.SendCommandToPrinter(advanceToBlackBar);
}
else if (radbtnGap.Checked)
{
MessageBox.Show(advanceToGap);
PrintUtils.SendCommandToPrinter(advanceToGap);
}
Could it be that this little "break in the action" is beneficial somehow?
UPDATE 5
Note: There is no "SerialPort.Flush" Maybe:
serialPort.Close();
...is accomplishing the same thing?
The SGD commands are well-formed. The intermittent behavior that you describe makes me think the problem originates in how consistently the printer actually receives the command, and not the syntax of the command itself. And generally speaking, no, you do not have to change other commands in order to make this command work. Since you can successfully send the command via Zebra Setup Utilities and get the desired behavior, then you should be able to do the same through your code.
Are you programmatically sending the commands over USB or over something else (Bluetooth, TCP, etc.)? You mentioned USB while using Zebra Setup Utilities, but what about in your code?
Can you provide the code underneath the hood of PrintUtils.SendCommandToPrinter()? I am not familiar with this API. Which API is it?
At the lowest levels of a connection you will often be calling 'write()' or 'writeData()' or something like that. Sometimes 'write' commands return the number of bytes written. If you can dig into your code a bit, perhaps there is a 'write' command that returns that value and you can verify yourself that the return value equals the length of the intended message (including new line characters).
Depending on the lower level API, there also may be a flush() command lying around that forcibly pushes all data in a stream to the other end. Again, this depends on what API you're using underneat the hood of 'PrintUtils'.
In the past I have seen inconsistent behavior with USB communication. You should make sure that your firmware is as up-to-date as possible. Your QLn220 is currently on v68.18.0Z: http://www.zebra.com/id/zebra/na/en/index/drivers_downloads/firmware/results.html?productType=6. You can check your current version by sending:
! U1 getvar "appl.name"
At the end of the day, you could always immediately query the printer for its gap/bar mode after setting it. This will cause as an additional delay in your program execution, but it is a good way of making sure that whatever you sent has actually taken effect.
for those with issues with labels printing too long, we had to set all our printer widths correctly via the zebra pc util.. send these commands to the printer.. PW means printer width, and JUS means Save the settings...
^XA
^PW832
^JUS
^XZ
Also this command helped with double labels printing
Sensor Calibration Command (source: Functional List of ZPL Commands) zpl_manual.pdf
~JC
It works after adding some debug strings; in the print code:
MessageBox.Show(success.ToString()); //TODO: Remove after testing
return success;
...and in the setting code:
if (radbtnBar.Checked)
{
MessageBox.Show(advanceToBlackBar);
PrintUtils.SendCommandToPrinter(advanceToBlackBar);
}
else if (radbtnGap.Checked)
{
MessageBox.Show(advanceToGap);
PrintUtils.SendCommandToPrinter(advanceToGap);
}
WHY it works, I don't know, so I'm still wary. But, for now at least, it is working with this tweak.

Categories

Resources