Dear All:
I am writing a small program to deal with a RS232 device (serial port)
and I refer to the SerialPortExample and USBNotificationExample on the Apple Developer Website.
I have established my own dictionary to lookup my device and my goal is to create the hot plug in/out function.
----Question----
So far I can get the device path while I plugin my device and the message "Device removed" while I plug it out.
But when I plug the device in again the console will show the below message in the Quote Section and the the debugger will stop at the *bsdPath = '\0';
I try to read the Apple Online document, but I cannot find solution for this...please help. any reply will be highly appreciated.
this is the complete code .
I am writing a small program to deal with a RS232 device (serial port)
and I refer to the SerialPortExample and USBNotificationExample on the Apple Developer Website.
I have established my own dictionary to lookup my device and my goal is to create the hot plug in/out function.
----Question----
So far I can get the device path while I plugin my device and the message "Device removed" while I plug it out.
But when I plug the device in again the console will show the below message in the Quote Section and the the debugger will stop at the *bsdPath = '\0';
I try to read the Apple Online document, but I cannot find solution for this...please help. any reply will be highly appreciated.
[Switching to process 1321]
Running
Modem found with BSD path: /dev/cu.usbserial
Raw device removed.
Program received signal: EXC_BAD_ACCESS.
sharedlibrary apply-load-rules all
this is the complete code .
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <paths.h>
#include <termios.h>
#include <sysexits.h>
#include <sys/param.h>
#include <sys/select.h>
#include <sys/time.h>
#include <time.h>
#include <AvailabilityMacros.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/serial/IOSerialKeys.h>
#include <IOKit/serial/ioss.h>
#include <IOKit/IOBSD.h>
#include <mach/mach.h>
// globals
static IONotificationPortRef gNotifyPort;
static io_iterator_t gRawAddedIter;
static io_iterator_t gRawRemovedIter;
void SignalHandler(int sigraised);
void RawDeviceAdded(void *refCon, io_iterator_t serialPortIterator, char *bsdPath, CFIndex maxPathSize);
void RawDeviceRemoved(void *refCon, io_iterator_t serialPortIterator);
void SignalHandler(int sigraised)
{
printf("\nInterrupted\n");
// Clean up here
IONotificationPortDestroy(gNotifyPort);
if (gRawAddedIter)
{
IOObjectRelease(gRawAddedIter);
gRawAddedIter = 0;
}
if (gRawRemovedIter)
{
IOObjectRelease(gRawRemovedIter);
gRawRemovedIter = 0;
}
if (gBulkTestAddedIter)
{
IOObjectRelease(gBulkTestAddedIter);
gBulkTestAddedIter = 0;
}
if (gBulkTestRemovedIter)
{
IOObjectRelease(gBulkTestRemovedIter);
gBulkTestRemovedIter = 0;
}
// exit(0) should not be called from a signal handler. Use _exit(0) instead
//
_exit(0);
}
void RawDeviceAdded(void *refCon, io_iterator_t serialPortIterator, char *bsdPath, CFIndex maxPathSize)
{
io_object_t serialDevice; // mach_port_t
kern_return_t kernResult = KERN_FAILURE;
Boolean deviceFound = false;
// Initialize the returned path
*bsdPath = '\0'; // [B]debugger will stop at here[/B]
while ( (serialDevice = IOIteratorNext(serialPortIterator)) )
{
CFTypeRef bsdPathAsCFString;
// Get the callout device's path (/dev/cu.xxxxx). The callout device should almost always be
// used: kIOCalloutDeviceKey
// the dialin device (/dev/tty.xxxxx), kIODialinDeviceKey, would be used when monitoring a serial port for
// incoming calls, e.g. a fax listener.
bsdPathAsCFString = IORegistryEntryCreateCFProperty(serialDevice,
CFSTR(kIOCalloutDeviceKey),
kCFAllocatorDefault,
0);
if (bsdPathAsCFString)
{
Boolean result;
// Convert the path from a CFString to a C (NUL-terminated) string for use
// with the POSIX open() call.
result = CFStringGetCString(bsdPathAsCFString,
bsdPath,
maxPathSize,
kCFStringEncodingUTF8);
CFRelease(bsdPathAsCFString);
if (result)
{
// check the bsdPath if it is an empty array
if (!bsdPath[0])
{
printf("No modem port found.\n");
//return EX_UNAVAILABLE;
}
else
{
printf("Modem found with BSD path: %s", bsdPath);
deviceFound = true;
kernResult = KERN_SUCCESS;
}
}
}
printf("\n");
// Release the io_object_t now that we are done with it.
(void) IOObjectRelease(serialDevice);
}
}
void RawDeviceRemoved(void *refCon, io_iterator_t serialPortIterator)
{
kern_return_t kr;
io_object_t obj;
while ( (obj = IOIteratorNext(serialPortIterator)) )
{
printf("Raw device removed.\n");
kr = IOObjectRelease(obj);
}
}
int main (int argc, const char * argv[])
{
kern_return_t kernResult; // on PowerPC this is an int (4 bytes)
/*
* error number layout as follows (see mach/error.h):
*
* hi lo
* | system(6) | subsystem(12) | code(14) |
*/
//----------Handler Secrion---------
mach_port_t masterPort;
sig_t oldHandler;
// Set up a signal handler so we can clean up when we're interrupted from the command line
// Otherwise we stay in our run loop forever.
oldHandler = signal(SIGINT, SignalHandler);
if (oldHandler == SIG_ERR)
printf("Could not establish new signal handler");
// first create a master_port for my task
kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort);
if (kernResult || !masterPort)
{
printf("ERR: Couldn't create a master IOKit Port(%08x)\n", kernResult);
return -1;
}
//---------Create Dictionary,Find Device-----------
CFMutableDictionaryRef devicesToMatchDictionary;
/*! @function IOServiceMatching
@abstract Create a matching dictionary that specifies an IOService class match.
@discussion A very common matching criteria for IOService is based on its class. IOServiceMatching will create a matching dictionary that specifies any IOService of a class, or its subclasses. The class is specified by C-string name.
@param name The class name, as a const C-string. Class matching is successful on IOService's of this class or any subclass.
@result The matching dictionary created, is returned on success, or zero on failure. The dictionary is commonly passed to IOServiceGetMatchingServices or IOServiceAddNotification which will consume a reference, otherwise it should be released with CFRelease by the caller. */
// Serial devices are instances of class IOSerialBSDClient
// see "Accessing Hardwares From Applications.pdf",
// page 33 - Setting Up a Matching Dictionary to Find Device Files
devicesToMatchDictionary = IOServiceMatching(kIOSerialBSDServiceValue); // IOSerialBSDClient
if (devicesToMatchDictionary == NULL)
{
printf("IOServiceMatching returned a NULL dictionary.\n");
printf("Can't create a Serial Port Device matching dictionary\n");
mach_port_deallocate(mach_task_self(), masterPort);
return -1;
}
else
{
/*!
@function CFDictionarySetValue
Sets the value of the key in the dictionary.
@param theDict The dictionary to which the value is to be set. If this
parameter is not a valid mutable CFDictionary, the behavior is
undefined. If the dictionary is a fixed-capacity dictionary and
it is full before this operation, and the key does not exist in
the dictionary, the behavior is undefined.
@param key The key of the value to set into the dictionary. If a key
which matches this key is already present in the dictionary, only
the value is changed ("add if absent, replace if present"). If
no key matches the given key, the key-value pair is added to the
dictionary. If added, the key is retained by the dictionary,
using the retain callback provided
when the dictionary was created. If the key is not of the sort
expected by the key retain callback, the behavior is undefined.
@param value The value to add to or replace into the dictionary. The value
is retained by the dictionary using the retain callback provided
when the dictionary was created, and the previous value if any is
released. If the value is not of the sort expected by the
retain or release callbacks, the behavior is undefined.
*/
CFDictionarySetValue(devicesToMatchDictionary,
CFSTR(kIOSerialBSDTypeKey), // IOSerialBSDClientType
CFSTR(kIOSerialBSDRS232Type)); // IORS232SerialStream
// we are going to set one more value into dictionary
CFDictionarySetValue(devicesToMatchDictionary,
CFSTR(kIOTTYBaseNameKey), // IOTTYBaseName
CFSTR("usbserial")); // usbserial
// Each serial device object has a property with key
// kIOSerialBSDTypeKey and a value that is one of kIOSerialBSDAllTypes,
// kIOSerialBSDModemType, or kIOSerialBSDRS232Type. You can experiment with the
// matching by changing the last parameter in the above call to CFDictionarySetValue.
}
// Create a notification port and add its run loop event source to our run loop
// This is how async notifications get set up.
gNotifyPort = IONotificationPortCreate(masterPort);
CFRunLoopSourceRef runLoopSource;
// use the gNotifyPort (notification object) received from IONotificationPortCreate
runLoopSource = IONotificationPortGetRunLoopSource(gNotifyPort);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
// Retain additional references because we use this same dictionary with four calls to
// IOServiceAddMatchingNotification, each of which consumes one reference.
devicesToMatchDictionary = (CFMutableDictionaryRef) CFRetain( devicesToMatchDictionary );
devicesToMatchDictionary = (CFMutableDictionaryRef) CFRetain( devicesToMatchDictionary );
devicesToMatchDictionary = (CFMutableDictionaryRef) CFRetain( devicesToMatchDictionary );
// Now set up two notifications, one to be called when a raw device is first matched by I/O Kit, and the other to be
// called when the device is terminated.
kernResult = IOServiceAddMatchingNotification(gNotifyPort, // the notification object you received from IONotificationPortCreate
kIOFirstMatchNotification, // A constant defining the type of event you want notification of, such as device registration or termination (these constants are defined in IOKitKeys.h in the i/O Kit Framework)
devicesToMatchDictionary, // the Core Foundation matching dictionary you've created
RawDeviceAdded, // the function you want called
NULL, // An optional reference constant for your callback function's use
&gRawAddedIter); // An io_iterator_t object to access the list of matching devices
int fileDescriptor;
char bsdPath[MAXPATHLEN];
RawDeviceAdded(NULL, gRawAddedIter, bsdPath, sizeof(bsdPath)); // Iterate once to get already-present devices and arm the notification
kernResult = IOServiceAddMatchingNotification(gNotifyPort,
kIOTerminatedNotification,
devicesToMatchDictionary,
RawDeviceRemoved,
NULL,
&gRawRemovedIter);
RawDeviceRemoved(NULL, gRawRemovedIter); // Iterate once to arm the notification
// Now done with the master_port
mach_port_deallocate(mach_task_self(), masterPort);
masterPort = 0;
// Start the run loop. Now we'll receive notifications.
CFRunLoopRun();
// We should never get here
return 0;
// // Open specified serial port
// fileDescriptor = OTOpenSerialPort(bsdPath);
// if (-1 == fileDescriptor)
// {
// return EX_IOERR;
// }
//
//
// if (OTInitializeDevice(fileDescriptor))
// {
// printf("Modem initialized successfully.\n");
// }
// else {
// printf("Could not initialize modem.\n");
// }
//CloseSerialPort(fileDescriptor);
//printf("Modem port closed.\n");
}