Redpark SDKでMonoTouchを使用し、ここにあるObjective-Cで記述されたRedparkシリアルケーブルのサンプルプログラムをC#で複製しようとしています(Xcodeで完全に実行できました)。
https://github.com/bjepson/iPhone-Arduino-Simple-Switch
ここにある既存のバインディングを使用しました:
https://github.com/mono/monotouch-bindings/tree/master/Redpark
プロジェクトで使用する.dllを作成しました。私のプロジェクトでは、書き込もうとするまで、すべてが順調に進んでいます(cableConnectedおよびcableDisconnectedデリゲートコールバックを正常に機能させることができました)。書き込み機能を使用しようとすると、プログラムがSIGSEGVでクラッシュします。
Stacktrace:
at MonoTouch.RedPark.RscMgr.Write (int16,uint) <IL 0x00010, 0x00113>
at tester2.tester2ViewController.toggleLED (MonoTouch.Foundation.NSObject) [0x00069] in /Users/salgarcia/Projects/tester2/tester2/tester2ViewController.cs:57
at (wrapper runtime-invoke) object.runtime_invoke_dynamic (intptr,intptr,intptr,intptr) <0xffffffff>
at MonoTouch.UIKit.UIApplication.Main (string[],string,string) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38
at tester2.Application.Main (string[]) [0x00000] in /Users/salgarcia/Projects/tester2/tester2/Main.cs:17
at (wrapper runtime-invoke) object.runtime_invoke_dynamic (intptr,intptr,intptr,intptr) <0xffffffff>
Native stacktrace:
0 tester2 0x001c2a25 mono_handle_native_sigsegv + 244
1 tester2 0x001af065 mono_sigsegv_signal_handler + 172
2 libsystem_c.dylib 0x329f17ed _sigtramp + 48
3 tester2 0x00003a63 __inline_memcpy_chk + 30
4 tester2 0x00003a63 __inline_memcpy_chk + 30
5 tester2 0x00004011 -[RscMgr writeRscMessage:Length:MsgData:] + 220
6 tester2 0x00004131 -[RscMgr write:Length:] + 100
7 tester2 0x000438d8 wrapper_managed_to_native_ApiDefinition_Messaging_int_objc_msgSend_short_UInt32_intptr_intptr_int16_uint + 256
8 tester2 0x001aa024 tester2_tester2ViewController_toggleLED_MonoTouch_Foundation_NSObject + 680
9 tester2 0x000f76c0 wrapper_runtime_invoke_object_runtime_invoke_dynamic_intptr_intptr_intptr_intptr + 200
10 tester2 0x001b0843 mono_jit_runtime_invoke + 1054
11 tester2 0x0022c40f mono_runtime_invoke + 90
12 tester2 0x001ad14d native_to_managed_trampoline_tester2_tester2ViewController_toggleLED + 220
13 CoreFoundation 0x3553f3fd -[NSObject performSelector:withObject:withObject:] + 52
14 UIKit 0x33034e07 -[UIApplication sendAction:to:from:forEvent:] + 62
15 UIKit 0x33034dc3 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 30
16 UIKit 0x33034da1 -[UIControl sendAction:to:forEvent:] + 44
17 UIKit 0x33034b11 -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 492
18 Foundation 0x350ff933 __NSFireDelayedPerform + 414
19 CoreFoundation 0x355b9a33 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 14
20 CoreFoundation 0x355b9699 __CFRunLoopDoTimer + 364
21 CoreFoundation 0x355b826f __CFRunLoopRun + 1206
22 CoreFoundation 0x3553b4a5 CFRunLoopRunSpecific + 300
23 CoreFoundation 0x3553b36d CFRunLoopRunInMode + 104
24 GraphicsServices 0x371d7439 GSEventRunModal + 136
25 UIKit 0x33047cd5 UIApplicationMain + 1080
26 tester2 0x0001fcc4 wrapper_managed_to_native_MonoTouch_UIKit_UIApplication_UIApplicationMain_int_string___intptr_intptr + 240
27 tester2 0x001a9744 tester2_Application_Main_string__ + 152
28 tester2 0x000f76c0 wrapper_runtime_invoke_object_runtime_invoke_dynamic_intptr_intptr_intptr_intptr + 200
29 tester2 0x001b0843 mono_jit_runtime_invoke + 1054
30 tester2 0x0022c40f mono_runtime_invoke + 90
31 tester2 0x0022f123 mono_runtime_exec_main + 306
32 tester2 0x00232a4f mono_runtime_run_main + 482
33 tester2 0x001b529f mono_jit_exec + 94
34 tester2 0x00271c70 main + 2216
35 tester2 0x00004860 start + 40
=================================================================
Got a SIGSEGV while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries
used by your application.
=================================================================
問題の可能性があるものの入力を探しています(つまり、シリアルポートが実際に開かれなかった、「txbuffer」に間違ったデータ型を使用している可能性がある、バインディングが適切に実装されていない、デリゲートを適切に設定していない) 、など)これに関するフィードバックをいただければ幸いです。
参考までに、C#/MonoTouch実装と一緒にObjective-C実装を示します。
RedparkライブラリのObjective-C「.h」ファイル
#import <Foundation/Foundation.h>
#import <ExternalAccessory/ExternalAccessoryDefines.h>
#import <ExternalAccessory/EAAccessoryManager.h>
#import <ExternalAccessory/EAAccessory.h>
#import <ExternalAccessory/EASession.h>
#include "redparkSerial.h"
enum
{
kMsrCts = 0x01,
kMsrRi = 0x02,
kMsrDsr = 0x04,
kMsrDcd = 0x08,
};
enum {
kRSC_StreamBufferSize = 4096,
kRSC_MaxMessageDataLength = 230,
kRSC_SerialReadBufferSize = 4096,
kRsc_TxFifoSize = 256,
kRSC_NoPasscode = 0
};
typedef enum DataSizeType
{
kDataSize7 = SERIAL_DATABITS_7,
kDataSize8 = SERIAL_DATABITS_8
} DataSizeType;
typedef enum ParityType
{
kParityNone = SERIAL_PARITY_NONE,
kParityOdd = SERIAL_PARITY_ODD,
kParityEven = SERIAL_PARITY_EVEN
} ParityType;
typedef enum StopBitsType
{
kStopBits1 = STOPBITS_1,
kStopBits2 = STOPBITS_2
} StopBitsType;
@protocol RscMgrDelegate;
@interface RscMgr : NSObject <NSStreamDelegate> {
id <RscMgrDelegate> theDelegate;
// EA api variables
EASession *theSession;
EAAccessory *theAccessory;
NSArray *supportedProtocols;
NSString *connectedProtocol;
// rsc port control/info structures
serialPortConfig portConfig;
serialPortStatus portStatus;
serialPortControl portControl;
// EASession stream handling
// for collecting RSC Messages
unsigned char *rxStreamBuffer;
int rxCount;
int rxCountTotal;
int txCountTotal;
int rxRemain;
int readLen;
unsigned char *txStreamBuffer;
int txIn;
int txOut;
int txStreamEmpty;
// internal dtr and rts state bits
int dtrState;
int rtsState;
// serial data buffer
// for collecting serial bytes received from the serial port
UInt8 *serialReadBuffer;
int serialReadIn;
int serialReadOut;
int serialReadBytesAvailable;
BOOL encodingEnabled;
UInt32 thePasscode;
}
- (void) setDelegate:(id <RscMgrDelegate>) delegate;
// Initializes the RscMgr and reigsters for accessory connect/disconnect notifications.
- (id) init;
// establish communication with the Redpark Serial Cable. This call will also
// configure the serial port based on defaults or prior calls to set the port config
// (see setBaud, setDataSize, ...)
- (void) open;
// simple serial port config interface
// can be called anytime (even after open: call)
- (void) setBaud:(int)baud;
- (void) setDataSize:(DataSizeType)dataSize;
- (void) setParity:(ParityType)parity;
- (void) setStopBits:(StopBitsType)stopBits;
// read write serial bytes
- (int) write:(UInt8 *)data Length:(UInt32)length;
- (int) read:(UInt8 *)data Length:(UInt32)length;
- (int) getReadBytesAvailable;
/*
returns a bit field (see redparkSerial.h)
0-3 current modem status bits for CTS, RI, DSR, DCD, 4-7 previous modem status bits
MODEM_STAT_CTS 0x01
MODEM_STAT_RI 0x02
MODEM_STAT_DSR 0x04
MODEM_STAT_DCD 0x08
*/
- (int) getModemStatus;
// returns true if DTR is asserted
- (BOOL) getDtr;
// returns true if RTS is asserted
- (BOOL) getRts;
// set DTR state
- (void) setDtr:(BOOL)enable;
// set RTS state
- (void) setRts:(BOOL)enable;
// advanced (full) serial port config interface (see redparkSerial.h)
- (void) setPortConfig:(serialPortConfig *)config RequestStatus:(BOOL)reqStatus;
- (void) setPortControl:(serialPortControl *)control RequestStatus:(BOOL)reqStatus;
- (void) getPortConfig:(serialPortConfig *) portConfig;
- (void) getPortStatus:(serialPortStatus *) portStatus;
// advanced advanced
// write a raw message
- (int) writeRscMessage:(int)cmd Length:(int)len MsgData:(UInt8 *)msgData;
// GPS cable only - requires loopback connector
- (void) testGpsCable;
@end
@protocol RscMgrDelegate <NSObject>
// Redpark Serial Cable has been connected and/or application moved to foreground.
// protocol is the string which matched from the protocol list passed to initWithProtocol:
- (void) cableConnected:(NSString *)protocol;
// Redpark Serial Cable was disconnected and/or application moved to background
- (void) cableDisconnected;
// serial port status has changed
// user can call getModemStatus or getPortStatus to get current state
- (void) portStatusChanged;
// bytes are available to be read (user calls read:)
- (void) readBytesAvailable:(UInt32)length;
@optional
// called when a response is received to a getPortConfig call
- (void) didReceivePortConfig;
// GPS Cable only - called with result when loop test completes.
- (void) didGpsLoopTest:(BOOL)pass;
@end
Objective-Cの「.h」ファイル
#import <UIKit/UIKit.h>
#import "RscMgr.h"
#define BUFFER_LEN 1024
@interface HelloArduinoViewController : UIViewController <RscMgrDelegate> {
RscMgr *rscMgr;
UInt8 rxBuffer[BUFFER_LEN];
UInt8 txBuffer[BUFFER_LEN];
UISwitch *toggleSwitch;
}
@property (nonatomic, retain) IBOutlet UISwitch *toggleSwitch;
- (IBAction)toggleLED:(id)sender;
@end
Objective-Cの「.m」ファイル
#import "HelloArduinoViewController.h"
@implementation HelloArduinoViewController
@synthesize toggleSwitch;
- (void)dealloc
{
[toggleSwitch release];
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
rscMgr = [[RscMgr alloc] init];
[rscMgr setDelegate:self];
}
- (void)viewDidUnload
{
[self setToggleSwitch:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (IBAction)toggleLED:(id)sender {
if (toggleSwitch.on) { // check the state of the button
txBuffer[0] = (int) '1';
} else {
txBuffer[0] = (int) '0';
}
// Send 0 or 1 to the Arduino
[rscMgr write:txBuffer Length:1];
}
#pragma mark - RscMgrDelegate methods
- (void) cableConnected:(NSString *)protocol {
[rscMgr setBaud:9600];
[rscMgr open];
}
- (void) cableDisconnected {
}
- (void) portStatusChanged {
}
- (void) readBytesAvailable:(UInt32)numBytes {
}
- (BOOL) rscMessageReceived:(UInt8 *)msg TotalLength:(int)len {
return FALSE;
}
- (void) didReceivePortConfig {
}
@end
私のC#/MonoTouchの実装
using System;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.RedPark;
namespace tester2
{
public partial class tester2ViewController : UIViewController
{
static RscMgr rscMgr;
MyRedparkDelegate delegate1;
short[] rxbuffer = new short[1024];
short[] txbuffer = new short[1024];
public tester2ViewController () : base ("tester2ViewController", null)
{
}
public override void DidReceiveMemoryWarning ()
{
base.DidReceiveMemoryWarning ();
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
rscMgr = new RscMgr();
delegate1 = new MyRedparkDelegate ();
rscMgr.SetDelegate(delegate1);
}
public override void ViewDidUnload ()
{
base.ViewDidUnload ();
ReleaseDesignerOutlets ();
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown);
}
partial void toggleLED (NSObject sender)
{
if(toggleSwitch.On) {
txbuffer[0] = (int) '1';
} else {
txbuffer[0] = (int) '0';
}
rscMgr.Write (txbuffer[0], 1);
}
public class MyRedparkDelegate : RscMgrDelegate
{
public MyRedparkDelegate ()
{
}
public override void CableConnected (string protocol)
{
rscMgr.SetBaud (9600);
rscMgr.Open ();
}
public override void CableDisconnected ()
{
}
public override void PortStatusChanged ()
{
}
public override void ReadBytesAvailable (uint length)
{
}
}
}
}