Using the Redpark SDK in MonoTouch
-
30-06-2021 - |
문제
I am attempting to use MonoTouch with the Redpark SDK and replicate in C# a Redpark serial cable example program written in Objective-C found here (that I was able to run perfectly in Xcode):
https://github.com/bjepson/iPhone-Arduino-Simple-Switch
I used an existing binding found here:
https://github.com/mono/monotouch-bindings/tree/master/Redpark
and created a .dll to use with my project. In my project, everything has been going smoothly (I was able to get the cableConnected and cableDisconnected delegate callbacks working well) up until trying to write. When I attempt to use the Write function, the program crashes with a 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.
=================================================================
I'm looking for input for what might be the problem (i.e. the Serial port actually did not get opened, I could be using the wrong data type for "txbuffer", the binding was not implemented properly, I am not setting the delegate properly, etc.) Any feedback on this would be greatly appreciated!
For reference, here is the Objective-C implementation alongside my C#/MonoTouch implementation:
Objective-C ".h" file for Redpark library
#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" file
#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" file
#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
My C#/MonoTouch implementation
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)
{
}
}
}
}
해결책
The problem was solved in my MonoTouch implementation code, where I found that I needed to pass the data being written by reference, so I changed the Write in the code above to
rscMgr.Write(ref txbuffer[0],1);
and it worked as expected. It helped thoroughly reading the Redpark Serial cable SDK User guide that came with the SDK download.