在 MonoTouch 中使用 Redpark SDK
Posted
技术标签:
【中文标题】在 MonoTouch 中使用 Redpark SDK【英文标题】:Using the Redpark SDK in MonoTouch 【发布时间】:2012-09-08 18:15:08 【问题描述】:我正在尝试将 MonoTouch 与 Redpark SDK 一起使用,并在 C# 中复制一个用 Objective-C 编写的 Redpark 串行电缆示例程序(我可以在 Xcode 中完美运行):
https://github.com/bjepson/iPhone-Arduino-Simple-Switch
我使用了在这里找到的现有绑定:
https://github.com/mono/monotouch-bindings/tree/master/Redpark
并创建了一个 .dll 用于我的项目。在我的项目中,一切都进行得很顺利(我能够让 cableConnected 和 cableDisconnected 委托回调正常工作)直到尝试编写。当我尝试使用 Write 函数时,程序会因 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)
【问题讨论】:
您需要发布RscMgr
的 Obj-C 头文件,以便有人帮助您。
我认为这需要特殊的硬件来测试?
@miguel.de.icaza 只是用于这个特定问题的 redpark 串行电缆,但最后只是一个配备串行通信的设备(我只是在这个示例项目中使用基本的 arduino)
【参考方案1】:
问题在我的MonoTouch实现代码中解决了,发现需要通过引用来传递正在写入的数据,所以将上面代码中的Write改成
rscMgr.Write(ref txbuffer[0],1);
它按预期工作。它有助于彻底阅读 SDK 下载随附的 Redpark 串行电缆 SDK 用户指南。
【讨论】:
以上是关于在 MonoTouch 中使用 Redpark SDK的主要内容,如果未能解决你的问题,请参考以下文章
RedPark 无法从串口读取数据:UIViewController 与 UINavigationController
帮助在monotouch中绑定一个静态objective-c库
我应该使用哪些 Instruments 工具来了解我的 Monotouch 应用程序的内存使用情况?