CNCopyCurrentNetworkInfo() is returning bad data - iphone

Apple introduced the CNCopyCurrentNetworkInfo() function in OS 4.1.
https://developer.apple.com/library/ios/#documentation/SystemConfiguration/Reference/CaptiveNetworkRef/Reference/reference.html#//apple_ref/doc/c_ref/kCNNetworkInfoKeySSIDData
According to the documentation it should:
Return the current network info for a given network interface.
However, when used it seems to return the correct SSID (readable network name) but a garbage BSSID(the MAC address of the Wireless Access Point). I have tried this connected to multiple different networks with two different iPads and the results are the same.
On my home network, the function returns:
{
BSSID = "0:19:db:8:5c:cc";
SSID = "Das Boot";
SSIDDATA = <44617320 426f6f74>;
}
In reality, the BSSID of my router is 0:4:ed:66:81:xx where the xx definitely is not cc
Does anyone have experience using this function and have I missed something obvious (more likely) or is this an Apple bug (much less likely) ?
Any input is greatly appreciated,
Nicke.

Related

How to read Analog Output Holding Registers on Advantech ADAM 6717 through ModBus TCP

I've been exploring the ADAM 6717 from Advantech.
This is the ModBus address table for said device:
At first I wanted to modify the value of the Digital output channel 0(DO0), so, as can be seen from the picture above, such address is the 0x0017.
I succeed at this by using a ModBus tool and the following settings:
Sending either "On" or "Off", turns On and off a LED connected to that output. Everything runs smoothly according to my expectation up to this point.
The problem arises when I want to read the Analog Input channel 6 or equivalently, address 400431~40044.
Since that address lies on the Analog Output Holding Registers part of the address table, I though that the following settings would accomplish the job:
However, as can be seen above, the reading shows 0.0 when there is actually 6V connected to that input (a potentiometer)
It is worth mentioning that I've made sure to enable the AI6 channel as well as setting it to Voltage mode instead of current. Also, the web utility for the device shows the AI6 reading correctly as I change the potentiometer's resistance value.
So the problem doesn't lie in the connection from the potentiometer to the AI6 but somewhere else.
Out of nothing and leaving aside what I think I know on this topic, I though of changing the function from 0x03 to 0x04
However, the response is exactly the same.
It bugs me that I can read and write values to the output coils but not the Analog output holding registers.
Is there any configuration that I might be missing over here?
Thanks in advance.
Device settings:
IP address: 10.0.0.1
Port in which the ModBus service is running: 5020

How to get Device Instance Path from Windows kernel driver?

Take a look at this example: a USB device in Windows 7 is reported to have Device instance path(DevinstPath) USB\VID_1EAB&PID_0501\7&25C389C1&0&1 and I know exactly that it corresponds to the so-called hardware-key(hwkey) in registry.
Now my question is: When my KMDF driver code has WDFDEVICE handle for that USB device, how can I know its DevinstPath?
I know I can
send a BusQueryDeviceID to achieve the so-called device-id USB\VID_1EAB&PID_0501;
send a BusQueryInstanceID to achieve the so-called instance-id 1 .
But I don't know how to get the so-called "instance-path". Could some kernel guru kindly tell me how I can get that?
MSDN doc seems really vague on this!
BTW: I also realize that user-layer function SetupDiGetDeviceInstanceId actually returns the DevinstPath -- although it is named "InstanceId".
Device instance path can be queried using DEVPKEY_Device_InstanceId, using either WdfDeviceAllocAndQueryPropertyEx or IoGetDevicePropertyData (passing the WDM physical device object)
Device Instance id is autoincrement sequence.
You can find HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum in registry;
Rules:NextPareneID.XXXXXXXX.N
XXXXXX use UUID Calculation crc32 values(test ok)
N is 1~9
Device Instance id format is N&PareneID&random's number&index
enter image description here

Confusion over CoreMIDI Destinations

Given the following code if I use the first method in the if branch to obtain a MIDIDestination the code works correctly, and MIDI data is sent. If I use the second method from the else branch, no data is sent.
var client = MIDIClientRef()
var port = MIDIPortRef()
var dest = MIDIEndpointRef()
MIDIClientCreate("jveditor" as CFString, nil, nil, &client)
MIDIOutputPortCreate(client, "output" as CFString, &port)
if false {
dest = MIDIGetDestination(1)
} else {
var device = MIDIGetExternalDevice(0)
var entity = MIDIDeviceGetEntity(device, 0)
dest = MIDIEntityGetDestination(entity, 0)
}
var name: Unmanaged<CFString>?
MIDIObjectGetStringProperty(dest, kMIDIPropertyDisplayName, &name)
print(name?.takeUnretainedValue() as! String)
var gmOn : [UInt8] = [ 0xf0, 0x7e, 0x7f, 0x09, 0x01, 0xf7 ]
var pktlist = MIDIPacketList()
var current = MIDIPacketListInit(&pktlist)
current = MIDIPacketListAdd(&pktlist, MemoryLayout<MIDIPacketList>.stride, current, 0, gmOn.count, &gmOn)
MIDISend(port, dest, &pktlist)
In both cases the printed device name is correct, and the status of every call is noErr.
I have noticed that if I ask for the kMIDIManufacturerName property that I get different results - specifically using the first method I get Generic, from the USB MIDI interface to which the MIDI device is connected, and with the second method I get the value of Roland configured via the Audio MIDI Setup app.
The reason I want to use the second method is specifically so that I can filter out devices that don't have the desired manufacturer name, but as above I can't then get working output.
Can anyone explain the difference between these two methods, and why the latter doesn't work, and ideally offer a suggestion as to how I can work around that?
It sounds like you want to find only the MIDI destination endpoints to talk to a certain manufacturer's devices. Unfortunately that isn't really possible, since there is no protocol for discovering what MIDI devices exist, what their attributes are, and how they are connected to the computer.
(Remember that MIDI is primitive 1980s technology. It doesn't even require bidirectional communication. There are perfectly valid MIDI setups with MIDI devices that you can send data to, but can never receive data from, and vice versa.)
The computer knows what MIDI interfaces are connected to it (for instance, a USB-MIDI interface). CoreMIDI calls these "Devices". You can find out how many there are, how many ports each has, etc. But there is no way to find out anything about the physical MIDI devices like keyboards and synthesizers that are connected to them.
"External devices" are an attempt to get around the discovery problem. They are the things that appear in Audio MIDI Setup when you press the "Add Device" button. That's all!
Ideally your users would create an external device for each physical MIDI device in their setup, enter all the attributes of each one, and set up all the connections in a way that perfectly mirrors their physical MIDI cables.
Unfortunately, in reality:
There may not be any external devices. There is not much benefit to creating them in Audio MIDI Setup, and it's a lot of boring data entry, so most people don't bother.
If there are external devices, you can't trust any of the information that the users added. The manufacturer might not be right, or might be spelled wrong, for instance.
It's pretty unfriendly to force your users to set things up in Audio MIDI Setup before they can use your software. Therefore, no apps do that... and therefore nobody sets anything up in Audio MIDI Setup. It's a chicken-and-egg problem.
Even if there are external devices, your users might want to send MIDI to other endpoints (like virtual endpoints created by other apps) that are not apparently connected to external devices. You should let them do what they want.
The documentation for MIDIGetDevice() makes a good suggestion:
If a client iterates through the devices and entities in the system, it will not ever visit any virtual sources and destinations created by other clients. Also, a device iteration will return devices which are "offline" (were present in the past but are not currently present), while iterations through the system's sources and destinations will not include the endpoints of offline devices.
Thus clients should usually use MIDIGetNumberOfSources, MIDIGetSource, MIDIGetNumberOfDestinations and MIDIGetDestination, rather iterating through devices and entities to locate endpoints.
In other words: use MIDIGetNumberOfDestinations and MIDIGetDestination to get the possible destinations, then let your users pick one of them. That's all.
If you really want to do more:
Given a destination endpoint, you can use MIDIEndpointGetEntity and MIDIEndpointGetDevice to get to the MIDI interface.
Given any MIDI object, you can find its connections to other objects. Use MIDIObjectGetDataProperty to get the value of property kMIDIPropertyConnectionUniqueID, which is an array of the unique IDs of connected objects. Then use MIDIObjectFindByUniqueID to get to the object. The outObjectType will tell you what kind of object it is.
But that's pretty awkward, and you're not guaranteed to find any useful information.
Based on a hint from Kurt Revis's answer, I've found the solution.
The destination that I needed to find is associated with the source of the external device, with the connection between them found using the kMIDIPropertyConnectionUniqueID property of that source.
Replacing the code in the if / else branch in the question with the code below works:
var external = MIDIGetExternalDevice(0)
var entity = MIDIDeviceGetEntity(external, 0)
var src = MIDIEntityGetSource(entity, 0)
var connID : Int32 = 0
var dest = MIDIObjectRef()
var type = MIDIObjectType.other
MIDIObjectGetIntegerProperty(src, kMIDIPropertyConnectionUniqueID, &connID)
MIDIObjectFindByUniqueID(connID, &dest, &type)
A property dump suggests that the connection Unique ID property is really a data property (perhaps containing multiple IDs) but the resulting CFData appears to be in big-endian format so reading it as an integer property instead seems to work fine.

JTAG: How do I know the width of the Instruction Register?

Assumed I have a JTAG-chain with several devices from different manufactures:
How does my software, which shall communicate with a specific system within that chain, known the length of the IR for all the others devices within the chain? I do have to know them to send a certain instruction to my device, right?
It is possible to detect the total length of all IR registers in your JTAG daisy-chain. It is also possible to detect the number of devices (or TAPs) in your chain. But you can't detect the individual IR length of a single TAP.
What you can do: You can read out the JTAG ID code register of all of you TAPs. The ID code register (in DR path) is always 32 bit and gets selected by test-logic-reset.
With the ID code you can identify the existing TAPs and look up in the datasheet the length of the individual IR registers.
And yes: In general you do have to know the individual IR length of all the TAPs in your chain to communicate with one of them.
try here: http://www.fpga4fun.com/JTAG3.html
When IR = '1...1', the BYPASS is selected.
The idea is to send a lot of '1' so regardless of IR length all devices will select BYPASS.

iPhone SSID Check is Unreliable

My application requires the user's iPhone to be connected to a 3rd party hardware device which broadcasts an SSID containing the Product Name (always the same) followed by a Unit Number (i.e. ProductName_123); essentially a Captive Network. Before allowing users to interact with my application, I ensure that the iPhone is currently connected to an appropriate SSID. I do so with the following method (I have obfuscated the product name for privacy reasons):
- (BOOL) connectedToHardwareDevice
{
/* Retrieve Interface Information */
CFArrayRef myArray = CNCopySupportedInterfaces();
CFDictionaryRef captiveNtwrkDict = CNCopyCurrentNetworkInfo(CFArrayGetValueAtIndex(myArray, 0));
/* Put network information into an iterable dictionary */
NSDictionary *dict = ( NSDictionary*) captiveNtwrkDict;
NSString* ssid = [dict objectForKey:#"SSID"];
/* Look for the Hardware Device name in the SSID */
rangeOfString:#"ProductName"].location == NSNotFound || ssid == NULL)
{
return false;
}
else
{
return true;
}
}
In my iPhone Wireless Network settings, I have declared a static IP for my testing device, which hastens the connection procedure as DHCP is avoided. However, often times I will open the application and be prompted with my "Not Connected" alert, which is triggered by the aforementioned method returning false. I find this exceptionally strange, considering I update a text field in a view with the current SSID, which will usually be correct despite the alert being shown.
My questions are as follows: Is there a more reliable means to achieve my goal? Am I going about this incorrectly? Is there some part of my method I could change in order to have more reliable results?
Thank you! If any additional information is required, please don't hesitate to ask!
My solution is to run the method again until a counter hits 20. If the counter hits 20 and the SSID is still not a match, then assume the user isn't connected to the hardware device and enter the "wait for WiFi connection" loop. This may not be the most graceful, but it works.