I am working on the connection between C# and a Siemens PLC (S7-1200). I've created a datablock (a.k.a. database) to which I need to read and eventually write. The connection to the PLC works, but I can't read anything from its datablock. It always give me the following error:
Error 33028 context is not supported. Step7 says: Function not implemented or error in telegram.
The number of the datablock is 311. I am starting at the first byte and I've only given up 1 as length.
I've also disabled Optimize block access, enabling does not solve this problem.
if (0 == lndConnection.connectPLC())
{
Byte[] bytes = new Byte[1];
res = lndConnection.readBytes(libnodave.daveDB ,311,0, 1, bytes);
if (res == 0)
MessageBox.Show(lndConnection.getS32().ToString());
else
{
mInt = 0;
MessageBox.Show("error " + res + " " + libnodave.daveStrerror(res));
}
}
I hope somebody can help me out with the problem.
The answer from Roatin Mart:
"S7-1200 has indirect access on by default. Check if Optimised Block access is disabled."
S7-1500 implements extended communication protocol which is not supported by libnodave.
It is possible though to connect and read/write global db blocks using the "old" protocol.
I have communicate successfully with both 1200 and 1500, but some additional setting plc-side are needed.
S7-1200
Only global DBs can be accessed.
The optimized block access must be turned off.
S7-1500
Only global DBs can be accessed.
The optimized block access must be turned off.
The access level must be “full” for the plc.
“connection mechanism” must allow GET/PUT for external partners
Details with screen-shots can be found at:
http://snap7.sourceforge.net/snap7_client.html
Hope it helps!
Cheers,
peter
Related
I am trying to write a WLAN fingerprinting program using NativeWifi in C#. To do this i run a loop to get the wlan information many times and then later use matlab to average / analyze the data.
The problem is that i get all the same values, even as i move about the house, when the program is running. From the internet i've seen that there is a cache that stores the data of available networks. I was wondering if there is a system call which resets this cache.
I have also seen this using the cmd call
netsh wlan show networks mode=bssid
this gives me the same values until i open the available wifi networks in my OS and if i run it again after, it will give different values.
edit: This system will be for my use only, so i would be comfortable starting over on a linux platform if there is a known library that can handle this for me. I don't even know what to google to even get the information, though. Anything related to "network cache" takes me to help threads of unrelated topics...
I will provide the relevant part of my code below:
public void get_info_instance(StreamWriter file)
{
try
{
foreach (WlanClient.WlanInterface wlanIface in client.Interfaces)
{
Wlan.WlanBssEntry[] wlanBssEntries = wlanIface.GetNetworkBssList();
foreach (Wlan.WlanBssEntry network in wlanBssEntries)
{
int rss = network.rssi;
byte[] macAddr = network.dot11Bssid;
string tMac = "";
for (int i = 0; i < macAddr.Length; i++)
{
tMac += macAddr[i].ToString("x2").PadLeft(2, '0').ToUpper();
}
file.WriteLine("Found network: " + System.Text.ASCIIEncoding.ASCII.GetString(network.dot11Ssid.SSID).ToString());
file.WriteLine("Signal: " + network.linkQuality + "%");
file.WriteLine("BSS Type: " + network.dot11BssType + ".");
file.WriteLine("RSSID: " + rss.ToString());
file.WriteLine("BSSID: " + tMac);
file.WriteLine(" ");
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Internally, netsh is powered by this API. What this means, is that calling netsh wlan show networks mode=bssid just returns the cache of the networks that showed up during the last scan. This is what you've discovered.
This means that in order to refresh this cache, you need to trigger a scan. If your C# library you are using includes it, you could make this happen on demand with a call to WlanScan. I am not sure which C# wrapper you are using, but it probably includes this function. When you get a scan complete notification (register with source WLAN_NOTIFICATION_SOURCE_ACM and look out for wlan_notification_acm_scan_list_refresh), the cache should be updated.
If you let me know which C# library you are using, maybe I can point you to the relevant functions.
You mentioned that opening the available networks causes the cache to refresh. This is because opening the available networks triggers a call to WlanScan.
Profiles are not relevant to the available network list -- profiles are what the Wlan service uses to keep track of which networks are configured on your machine -- deleting them does not make WlanSvc scan again. It may be a coincidence that deleting them happens to coincide with a scan, but it is more of a side effect than the designed usage.
edit: to subscribe to notifications using the Managed Wifi API you are using, this snippet should work:
wlanIface.WlanNotification += wlanIface_WlanNotification;
And the callback:
static void wlanIface_WlanNotification(Wlan.WlanNotificationData notifyData)
{
if (notifyData.notificationCode == (int)Wlan.WlanNotificationCodeAcm.ScanComplete)
{
Console.WriteLine("Scan Complete!");
}
}
You can test this by running this, then opening the available networks on Windows. You should see "Scan Complete" shortly after you open it each time. You can use a messagebox instead of Console.WriteLine if you prefer.
To trigger a scan yourself:
wlanIface.Scan();
for all
netsh wlan delete profile name=* i=*
you might not want to do it on all interfaces, and hard code the interface in there for faster result
One of my softwares need to change system proxies on Windows. Changing the HTTP proxy for LAN connections behind a router is easy, but I cannot find any information on how to change proxies for dialup or direct DSL (i.e. PPPoE) connections.
This is bad because a significant fraction of my clients are in China. In China, many people do not have more than one computer, and thus find a router wasteful. They simply connect their ADSL modem to their ethernet port and use PPPoE. Yes, this sucks for security and everything (one reason why botnets roam so freely in China) but it is reality and my software needs to work.
I also need code that gives me the list of all network connections. Just having code as in my related question that requires one to know the connection to edit would not work.
I also prefer something that would work by using the reg command. Simple C++ or C# code using the Windows API is also useful, but note that I'm using Racket, a language with a rather cumbersome FFI, which means that it would be best to minimize use of the Windows C API.
Assuming you are unable to use Windows native API calls, I’ll put my bit by providing a solution that only would require calls to Windows commands (reg) and array/strings manipulation, something that the "Racket" language must implement for sure.
This is not the cleanest way but given the requirements it should be a feasible solution for you.
Well, as you perhaps have noticed, the proxy configuration for the different connections is stored under the key: HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections
Under that key there’s a value that stores the DefaultConnectionSettings and another value that stores the SavedLegacySettings (both of type REG_BINARY). In addition to the two mentioned values there’s a value per each system connection (also of type REG_BINARY) that stores the connection configuration including the proxy settings. The name of the values equals the connection names.
Fortunately some guy have reverse engineered the structure of the BINARY data stored in those values.
Byte number zero always has a 3C or 46 - I couldn't find more information about this byte.The next three bytes are zeros.
Byte number 4 is a counter used by the 'Internet Options' property sheet (Internet explorer->Tools->Internet Options...). As you manually
change the internet setting (such as LAN settings in the Connections
tab), this counter increments.Its not very useful byte.But it MUST
have a value. I keep it zero always. The next three bytes are zeros
(Bytes 5 to 7).
Byte number 8 can take different values as per your settings. The value is :
09 when only 'Automatically detect settings' is enabled
03 when only 'Use a proxy server for your LAN' is enabled
0B when both are enabled
05 when only 'Use automatic configuration script' is enabled
0D when 'Automatically detect settings' and 'Use automatic configuration script' are enabled
07 when 'Use a proxy server for your LAN' and 'Use automatic configuration script' are enabled
0F when all the three are enabled.
01 when none of them are enabled. The next three bytes are zeros (Bytes 9 to B).
Byte number C (12 in decimal) contains the length of the proxy server address.For example a proxy server '127.0.0.1:80' has length 12
(length includes the dots and the colon).The next three bytes are
zeros (Bytes D to F).
Byte 10 (or 16 in decimal) contains the proxy server address - like '127.0.0.1:80' (where 80 is obviously the port number)
The byte immediatley after the address contians the length of additional information.The next three bytes are zeros. For example if
the 'Bypass proxy server for local addresses' is ticked, then this
byte is 07,the next three bytes are zeros and then comes a string i.e.
'' ( indicates that you are bypassing the proxy
server.Now since has 7 characters, the length is 07!). You
will have to experiment on your own for finding more about this. If
you dont have any additional info then the length is 0 and no
information is added.
The byte immediately after the additional info, is the length of the automatic configuration script address (If you dont have a script
address then you dont need to add anything,skip this step and goto
step 8).The next three bytes are zeros,then comes the address.
Finally, 32 zeros are appended.(I dont know why! Presumably to fill the binary blob, perhaps it is expected to be a certain length by
something, don't you wish windows had some source?)
Complete info can be found here.
With this info I think you can manage to obtain the values in. Just do reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections", properly parse the output and use reg again to write back the modifications.
I hope this helps.
You may use this c# code to change proxy server for VPN connections:
// host looks like "127.0.0.1:8080"
public static void EnableVPNProxy(string host)
{
RegistryKey RegKey = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Connections", true);
foreach (var name in RegKey.GetValueNames())
{
try
{
byte[] server = Encoding.ASCII.GetBytes(host);
byte[] current = (byte[])RegKey.GetValue(name);
byte[] data = new byte[100];
data[0] = current[0];
data[1] = data[2] = data[3] = data[4] = data[5] = data[6] = data[7] = 0;
data[8] = 3;
data[9] = data[10] = data[11] = 0;
data[12] = Convert.ToByte(server.Length);
data[13] = data[14] = data[15] = 0;
int i = 16;
foreach (var b in server)
{
data[i] = b;
i++;
}
for (var x = 0; x < 40; x++)
{
data[i] = 0;
i++;
}
RegKey.SetValue(name, data);
}
catch (Exception ex) { }
}
}
And enable proxy
EnableVPNProxy("127.0.0.1:8080");
I'm using Jon Skeet's (excellent) port of Google's Protocol Buffers to C#/.Net.
For practice, I have written a dummy Instant Messenger app that sends some messages down a socket. I have a message definition as follows:-
message InstantMessage {<br/>
required string Message = 1;<br/>
required int64 TimeStampTicks = 2; <br/>
}
When the sender serialises the message, it sends it really elegantly:-
...
InstantMessage.Builder imBuild = new InstantMessage.Builder();
imBuild.Message = txtEnterText.Text;
imBuild.TimeStampTicks = DateTime.Now.Ticks;
InstantMessage im = imBuild.BuildPartial();
im.WriteTo(networkStream);
...
This works great. But at the other end, I'm having trouble getting the ParseFrom to work.
I want to use:-
InstantMessage im = InstantMessage.ParseFrom(networkStream);
But instead I have had to read it to bytes and then parse it from here. This is obviously not ideal for a number of reasons. Current code is:-
while (true)
{
Byte[] byteArray = new Byte[10000000];
int intMsgLength;
int runningMsgLength = 0;
DateTime start = DateTime.Now;
while (true)
{
runningMsgLength += networkStream.Read(byteArray, runningMsgLength, 10000000 - runningMsgLength);
if (!networkStream.DataAvailable)
break;
}
InstantMessage im = InstantMessage.ParseFrom(byteArray.Take(runningMsgLength).ToArray());
When I try to use ParseFrom, control does not return to the calling method even when I know a valid GB message is on the wire.
Any advice would be gratefully received,
PW
Sorry for taking a while to answer this. As Marc says, protocol buffers don't have a terminator, and they aren't length prefixed unless they're nested. However, you can put on the length prefix yourself. If you look at MessageStreamIterator and MessageStreamWriter, you'll see how I do this - basically I pretend that I'm in the middle of a message, writing a nested message as field 1. Unfortunately when reading the message, I have to use internal details (BuildImpl).
There's now another API to do this: IMessage.WriteDelimitedTo and IBuilder.MergeDelimitedFrom. This is probably what you want at the moment, but I seem to remember there's a slight issue with it in terms of detecting the end of the stream (i.e. when there isn't another message to read). I can't remember whether there's a fix for it at the moment - I have a feeling it's changed in the Java version and I may not have ported the change yet. Anyway, that's definitely the area to look at.
Protobuf has no terminator - so either close the stream, or use your own length prefix etc. Protobuf-net exposes this easily via SerializeWithLenghtPrefix / DeserializeWithLengthPrefix.
Simply: without this, it can't know where each message ends, so keeps trying to read to the end of the stream.
Update
Turns out the error was in the crypto processor code, that is fixed. But now running into what seems like it might be a handshaking issue.
On first transmission, we get a single byte back from the device with value 0xFF(don't know why, the engineer I'm working with isn't too experienced with RS-232 either). Then, things run as normal (just sending the device one byte at a time, and waiting for a matching echo). However, neither the device nor the .NET app can send more than a couple of bytes at a time before one of them locks up and refuses to send or receive.
At work I'm writing an app that interfaces over RS232 with a crypto processor inside a device to reprogram flash modules inside the device.
To just take things slow and make sure all our headers are right, we're writing one byte at a time with SerialPort.Write(). However, when we run the code on the crypto processor, it reads an extra NULL in between each byte. When I test the .NET code on my local machine with two serial ports and a crossover cable, I capture the output in HyperTerminal or Putty and there are no extra NULLs when I view the log in Notepad++.
However, to further complicate things, when we manually type messages byte-per-byte via HyperTerminal to the crypto processor, it reads the input as a single byte only, no extra NULLs (as compared to the .NET app). Anybody have any experience with .NET doing mysterious things when it writes to a SerialPort?
We're initializing a test chunk with this:
byte[] testBytes = new byte[] { (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', (byte)'H' };
byte[] byteArray = new byte[256];
for (int i = 0; i < 32; i++)
{
testBytes.CopyTo(byteArray, i * 8);
}
And sending it with this:
public void StutterSend(byte[] data, long delayMs)
{
bool interactive = false;
if (delayMs < 0)
interactive = true;
for (int i = 0; i < data.Length; i++)
{
serialPort.Write(data, i, 1);
if (interactive)
{
WriteLine("Sent byte " + (i + 1) + " of " + data.Length + ". Press any key to send moar.");
Console.ReadKey();
}
else
{
double timer = DateTime.Now.TimeOfDay.TotalMilliseconds;
do { } while ((DateTime.Now.TimeOfDay.TotalMilliseconds - timer) < delayMs);
}
}
WriteLine("Done sending bytes.");
}
Our SerialPort is configured with all the matching parameters (stop bits, data bits, parity, baud rate, port name), and our handshake is set to None (it's just how our uart driver works).
Regarding your update, it sounds like your crypto processor has some more problems. Getting a 0xff back can be the result of an unexpected glitch of <= 1 bit time on the Tx line of the RS232 port. This is interpreted as a start bit by the PC. After the glitch, the Tx line returns to the mark state and now that the UART on the PC has a start bit, it interprets the "data" bits as all ones (the value for the mark state). The mark state is also the correct value for the stop bit(s) so your PC's UART has received a valid byte with a value of 0xff. Note that the glitch can be very fast relative to the RS232 data rate and still be interpreted as a start bit so have your engineer look at this line with an oscilloscope in normal mode/single sequence trigger to confirm this.
What is the Encoding property for the serialPort set to? The docs for SerialPort.Write( byte[], int, int) say that it runs its data through an Encoder object (which doesn't really make sense to me for a byte[]). It's supposed to default to ASCIIEncoding, but it seems like it might be set to something else. try explicitly setting it to ASCIIEncoding and see if that helps. I can't recall if this was an issue for me back when I did some serial port stuff in .NET to talk to an embedded board...
Note that even with ASCIIEncoding in use, you'll get some (probably unwanted) transformation of data - if you try to send something above value 127, the encoder will convert it to '?' since it's not a valid ASCII character. I can't recall off the top of my head how I got the serial port to simply leave my data alone - I'll have to dig around in some source code...
SerialPort sets the Parity property to Parity.None if you don't specify any. This means in case your receiver expects a Partity bit, it will never get one as long as you don't tell SerialPort explicitely to send along a Parity Bit with the transmitted data.
And the fact that it went well on HyperTerminal could be that HyperTerminal uses a Parity bit by default ( I don't know HyperTerminal well).
when i run this code :
CONADefinitions.CONAPI_FOLDER_INFO2 FolderInfo;
int iResult = 0;
IntPtr Buffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CONADefinitions.CONAPI_FOLDER_INFO2)));
iResult = CONAFileSystem.CONAFindNextFolder(hFindHandle, Buffer);
while (iResult == PCCSErrors.CONA_OK )
{
FolderInfo = (CONADefinitions.CONAPI_FOLDER_INFO2)Marshal.PtrToStructure(Buffer,typeof(CONADefinitions.CONAPI_FOLDER_INFO2));
//......................... i got an error msg here as follows:
// Error Messege:
FatalExecutionEngineError was detected Message: The runtime has encountered a
fatal error. The address of the error was at 0x7a0ba769, on thread 0x1294. The
error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe
or non-verifiable portions of user code. Common sources of this bug include
user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
how to use CONADefinitions.CONAPI_FOLDER_INFO2, coz when i use CONADefinitions.CONAPI_FOLDER_INFO it only gives me the name and lable of the device
but when is use CONADefinitions.CONAPI_FOLDER_INFO2 it gives me freeSize and TotalSize
please help
I'm not sure what that error means but if you want to get the drive's size, you can use
DriveInfo di = new DriveInfo("f"); //Put your mobile drive name
long totalBytes = di.TotalSize;
long freeBytes = di.TotalFreeSpace;
It is correct that you get the exception when you try and convert the data in the buffer to a different type of structure than was originally created by CONAFileSystem.CONAFindNextFolder.
You are trying to force a data structure of type CONADefinitions.CONAPI_FOLDER_INFO into a structure of type CONADefinitions.CONAPI_FOLDER_INFO2. They almost certainly have different lengths and so on so its extremely unlikely this method would ever work.
From experience with C++ development on the Symbian OS, the pattern Nokia are likely to be using here is one where they have subsequently developed a newer version of the API and so have created a newer version of the CONADefinitions.CONAPI_FOLDER_INFO structure (i.e. CONADefinitions.CONAPI_FOLDER_INFO2).
Assuming this is correct there are 3 likelihoods:
1) There is an enum parameter to the first function which specifies which version of the output structure is to be created.
2) There is a new function which returns the new structure e.g. CONAFileSystem.CONAFindFirstFolder2, CONAFileSystem.CONAFindNextFolder2
3) Nokia have developed the new version internally but not yet released it publicly.