How to get values from methods written in IOS plugin in unity? - ios

I am looking to get latitude and longitude values from an IOS plugin.The plugin code is given below which is a .mm file.
#import "iPhone_Sensors.h"
#import <CoreLocation/CoreLocation.h>
#import <CoreMotion/CoreMotion.h>
#include "iPhone_View.h"
#include "iPhone_OrientationSupport.h"
static bool gCompensateSensors = true;
bool gEnableGyroscope = false;
bool IsCompensatingSensors() { return gCompensateSensors; }
void SetCompensatingSensors(bool val) { gCompensateSensors = val;}
void UnityDidAccelerate(float x, float y, float z, NSTimeInterval timestamp);
struct Vector3f
{
float x, y, z;
};
struct Quaternion4f
{
float x, y, z, w;
};
inline float UnityReorientHeading(float heading)
{
if (IsCompensatingSensors())
{
float rotateBy = 0.f;
switch (UnityCurrentOrientation())
{
case portraitUpsideDown:
rotateBy = -180.f;
break;
case landscapeLeft:
rotateBy = -270.f;
break;
case landscapeRight:
rotateBy = -90.f;
break;
default:
break;
}
return fmodf((360.f + heading + rotateBy), 360.f);
}
else
{
return heading;
}
}
inline Vector3f UnityReorientVector3(float x, float y, float z)
{
if (IsCompensatingSensors())
{
Vector3f res;
switch (UnityCurrentOrientation())
{
case portraitUpsideDown:
{ res = (Vector3f){-x, -y, z}; }
break;
case landscapeLeft:
{ res = (Vector3f){-y, x, z}; }
break;
case landscapeRight:
{ res = (Vector3f){y, -x, z}; }
break;
default:
{ res = (Vector3f){x, y, z}; }
}
return res;
}
else
{
return (Vector3f){x, y, z};
}
}
static Quaternion4f gQuatRot[4] =
{ // { x*sin(theta/2), y*sin(theta/2), z*sin(theta/2), cos(theta/2) }
// => { 0, 0, sin(theta/2), cos(theta/2) } (since <vec> = { 0, 0, +/-1})
{ 0.f, 0.f, 0.f /*sin(0)*/, 1.f /*cos(0)*/}, // ROTATION_0, theta = 0 rad
{ 0.f, 0.f, (float)sqrt(2) * 0.5f /*sin(pi/4)*/, -(float)sqrt(2) * 0.5f /*cos(pi/4)*/}, // ROTATION_90, theta = pi/4 rad
{ 0.f, 0.f, 1.f /*sin(pi/2)*/, 0.f /*cos(pi/2)*/}, // ROTATION_180, theta = pi rad
{ 0.f, 0.f, -(float)sqrt(2) * 0.5f/*sin(3pi/4)*/, -(float)sqrt(2) * 0.5f /*cos(3pi/4)*/} // ROTATION_270, theta = 3pi/2 rad
};
inline void MultQuat(Quaternion4f& result, const Quaternion4f& lhs, const Quaternion4f& rhs)
{
result.x = lhs.w*rhs.x + lhs.x*rhs.w + lhs.y*rhs.z - lhs.z*rhs.y;
result.y = lhs.w*rhs.y + lhs.y*rhs.w + lhs.z*rhs.x - lhs.x*rhs.z;
result.z = lhs.w*rhs.z + lhs.z*rhs.w + lhs.x*rhs.y - lhs.y*rhs.x;
result.w = lhs.w*rhs.w - lhs.x*rhs.x - lhs.y*rhs.y - lhs.z*rhs.z;
}
inline Quaternion4f UnityReorientQuaternion(float x, float y, float z, float w)
{
if (IsCompensatingSensors())
{
Quaternion4f res, inp = {x, y, z, w};
switch (UnityCurrentOrientation())
{
case landscapeLeft:
MultQuat(res, inp, gQuatRot[1]);
break;
case portraitUpsideDown:
MultQuat(res, inp, gQuatRot[2]);
break;
case landscapeRight:
MultQuat(res, inp, gQuatRot[3]);
break;
default:
res = inp;
}
return res;
}
else
{
return (Quaternion4f){x, y, z, w};
}
}
void SetGyroRotationRate(int idx, float x, float y, float z);
void SetGyroRotationRateUnbiased(int idx, float x, float y, float z);
void SetGravity(int idx, float x, float y, float z);
void SetUserAcceleration(int idx, float x, float y, float z);
void SetAttitude(int idx, float x, float y, float z, float w);
static CMMotionManager *sMotionManager = nil;
static NSOperationQueue* sMotionQueue = nil;
// Current update interval or 0.0f if not initialized. This is returned
// to the user as current update interval and this value is set to 0.0f when
// gyroscope is disabled.
static float sUpdateInterval = 0.0f;
// Update interval set by the user. Core motion will be set-up to use
// this update interval after disabling and re-enabling gyroscope
// so users can set update interval, disable gyroscope, enable gyroscope and
// after that gyroscope will be updated at this previously set interval.
static float sUserUpdateInterval = 1.0f / 30.0f;
void SensorsCleanup()
{
if (sMotionManager != nil)
{
[sMotionManager stopGyroUpdates];
[sMotionManager stopDeviceMotionUpdates];
[sMotionManager stopAccelerometerUpdates];
[sMotionManager release];
sMotionManager = nil;
}
if (sMotionQueue != nil)
{
[sMotionQueue release];
sMotionQueue = nil;
}
}
void CoreMotionStart()
{
if (sMotionQueue == nil)
sMotionQueue = [[NSOperationQueue alloc] init];
if (sMotionManager == nil)
{
sMotionManager = [[CMMotionManager alloc] init];
if (sMotionManager.gyroAvailable && gEnableGyroscope)
{
[sMotionManager startGyroUpdates];
[sMotionManager setGyroUpdateInterval: sUpdateInterval];
}
if (sMotionManager.deviceMotionAvailable && gEnableGyroscope)
{
[sMotionManager startDeviceMotionUpdates];
[sMotionManager setDeviceMotionUpdateInterval: sUpdateInterval];
}
if (sMotionManager.accelerometerAvailable)
{
int frequency = UnityGetAccelerometerFrequency();
if (frequency > 0)
{
[sMotionManager startAccelerometerUpdatesToQueue: sMotionQueue withHandler: ^( CMAccelerometerData* data, NSError* error) {
Vector3f res = UnityReorientVector3(data.acceleration.x, data.acceleration.y, data.acceleration.z);
UnityDidAccelerate(res.x, res.y, res.z, data.timestamp);
}];
[sMotionManager setAccelerometerUpdateInterval: 1.0 / frequency];
}
}
}
}
void CoreMotionStop()
{
if (sMotionManager != nil)
{
[sMotionManager stopGyroUpdates];
[sMotionManager stopDeviceMotionUpdates];
}
}
void SetGyroUpdateInterval(int idx, float interval)
{
if (interval < (1.0f / 60.0f))
interval = (1.0f / 60.0f);
else if (interval > (1.0f))
interval = 1.0f;
sUserUpdateInterval = interval;
if (sMotionManager)
{
sUpdateInterval = interval;
[sMotionManager setGyroUpdateInterval: interval];
[sMotionManager setDeviceMotionUpdateInterval: interval];
}
}
float GetGyroUpdateInterval(int idx)
{
return sUpdateInterval;
}
void UpdateGyroData()
{
CMRotationRate rotationRate = { 0.0, 0.0, 0.0 };
CMRotationRate rotationRateUnbiased = { 0.0, 0.0, 0.0 };
CMAcceleration userAcceleration = { 0.0, 0.0, 0.0 };
CMAcceleration gravity = { 0.0, 0.0, 0.0 };
CMQuaternion attitude = { 0.0, 0.0, 0.0, 1.0 };
if (sMotionManager != nil)
{
CMGyroData *gyroData = sMotionManager.gyroData;
CMDeviceMotion *motionData = sMotionManager.deviceMotion;
if (gyroData != nil)
{
rotationRate = gyroData.rotationRate;
}
if (motionData != nil)
{
CMAttitude *att = motionData.attitude;
attitude = att.quaternion;
rotationRateUnbiased = motionData.rotationRate;
userAcceleration = motionData.userAcceleration;
gravity = motionData.gravity;
}
}
Vector3f reorientedRotRate = UnityReorientVector3(rotationRate.x, rotationRate.y, rotationRate.z);
SetGyroRotationRate(0, reorientedRotRate.x, reorientedRotRate.y, reorientedRotRate.z);
Vector3f reorientedRotRateUnbiased = UnityReorientVector3(rotationRateUnbiased.x, rotationRateUnbiased.y, rotationRateUnbiased.z);
SetGyroRotationRateUnbiased(0, reorientedRotRateUnbiased.x, reorientedRotRateUnbiased.y, reorientedRotRateUnbiased.z);
Vector3f reorientedUserAcc = UnityReorientVector3(userAcceleration.x, userAcceleration.y, userAcceleration.z);
SetUserAcceleration(0, reorientedUserAcc.x, reorientedUserAcc.y, reorientedUserAcc.z);
Vector3f reorientedG = UnityReorientVector3(gravity.x, gravity.y, gravity.z);
SetGravity(0, reorientedG.x, reorientedG.y, reorientedG.z);
Quaternion4f reorientedAtt = UnityReorientQuaternion(attitude.x, attitude.y, attitude.z, attitude.w);
SetAttitude(0, reorientedAtt.x, reorientedAtt.y, reorientedAtt.z, reorientedAtt.w);
}
bool IsGyroEnabled(int idx)
{
if (sMotionManager == nil)
return false;
return sMotionManager.gyroAvailable && sMotionManager.gyroActive;
}
bool IsGyroAvailable()
{
if (sMotionManager != nil)
return sMotionManager.gyroAvailable;
return false;
}
#interface LocationServiceDelegate : NSObject <CLLocationManagerDelegate>
#end
void
UnitySetLastLocation(double timestamp,
float latitude,
float longitude,
float altitude,
float horizontalAccuracy,
float verticalAccuracy);
void
UnitySetLastHeading(float magneticHeading,
float trueHeading,
float rawX, float rawY, float rawZ,
double timestamp);
struct LocationServiceInfo
{
private:
LocationServiceDelegate* delegate;
CLLocationManager* locationManager;
public:
LocationServiceStatus locationStatus;
LocationServiceStatus headingStatus;
float desiredAccuracy;
float distanceFilter;
LocationServiceInfo();
CLLocationManager* GetLocationManager();
};
LocationServiceInfo::LocationServiceInfo()
{
locationStatus = kLocationServiceStopped;
desiredAccuracy = kCLLocationAccuracyKilometer;
distanceFilter = 500;
headingStatus = kLocationServiceStopped;
}
static LocationServiceInfo gLocationServiceStatus;
CLLocationManager*
LocationServiceInfo::GetLocationManager()
{
if (locationManager == nil)
{
locationManager = [[CLLocationManager alloc] init];
delegate = [LocationServiceDelegate alloc];
locationManager.delegate = delegate;
}
return locationManager;
}
bool LocationService::IsServiceEnabledByUser()
{
return [CLLocationManager locationServicesEnabled];
}
void LocationService::SetDesiredAccuracy(float val)
{
gLocationServiceStatus.desiredAccuracy = val;
}
float LocationService::GetDesiredAccuracy()
{
return gLocationServiceStatus.desiredAccuracy;
}
void LocationService::SetDistanceFilter(float val)
{
gLocationServiceStatus.distanceFilter = val;
}
float LocationService::GetDistanceFilter()
{
return gLocationServiceStatus.distanceFilter;
}
void LocationService::StartUpdatingLocation()
{
if (gLocationServiceStatus.locationStatus != kLocationServiceRunning)
{
CLLocationManager* locationManager = gLocationServiceStatus.GetLocationManager();
locationManager.desiredAccuracy = gLocationServiceStatus.desiredAccuracy;
// Set a movement threshold for new events
locationManager.distanceFilter = gLocationServiceStatus.distanceFilter;
[locationManager startUpdatingLocation];
gLocationServiceStatus.locationStatus = kLocationServiceInitializing;
}
}
void LocationService::StopUpdatingLocation()
{
if (gLocationServiceStatus.locationStatus == kLocationServiceRunning)
{
[gLocationServiceStatus.GetLocationManager() stopUpdatingLocation];
gLocationServiceStatus.locationStatus = kLocationServiceStopped;
}
}
void LocationService::SetHeadingUpdatesEnabled(bool enabled)
{
if (enabled)
{
if (gLocationServiceStatus.headingStatus != kLocationServiceRunning &&
IsHeadingAvailable())
{
CLLocationManager* locationManager = gLocationServiceStatus.GetLocationManager();
[locationManager startUpdatingHeading];
gLocationServiceStatus.headingStatus = kLocationServiceInitializing;
}
}
else
{
if(gLocationServiceStatus.headingStatus == kLocationServiceRunning)
{
[gLocationServiceStatus.GetLocationManager() stopUpdatingHeading];
gLocationServiceStatus.headingStatus = kLocationServiceStopped;
}
}
}
bool LocationService::IsHeadingUpdatesEnabled()
{
return (gLocationServiceStatus.headingStatus == kLocationServiceRunning);
}
int UnityGetLocationStatus()
{
return gLocationServiceStatus.locationStatus;
}
int UnityGetHeadingStatus()
{
return gLocationServiceStatus.headingStatus;
}
bool LocationService::IsHeadingAvailable()
{
return [CLLocationManager headingAvailable];
}
#implementation LocationServiceDelegate
// Delegate method from the CLLocationManagerDelegate protocol.
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
gLocationServiceStatus.locationStatus = kLocationServiceRunning;
UnitySetLastLocation([newLocation.timestamp timeIntervalSince1970],
newLocation.coordinate.latitude,
newLocation.coordinate.longitude,
newLocation.altitude,
newLocation.horizontalAccuracy,
newLocation.verticalAccuracy);
}
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
gLocationServiceStatus.headingStatus = kLocationServiceRunning;
Vector3f reorientedRawHeading = UnityReorientVector3(newHeading.x, newHeading.y, newHeading.z);
UnitySetLastHeading(UnityReorientHeading(newHeading.magneticHeading),
UnityReorientHeading(newHeading.trueHeading),
reorientedRawHeading.x, reorientedRawHeading.y, reorientedRawHeading.z,
[newHeading.timestamp timeIntervalSince1970]);
}
- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager
{
return NO;
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error;
{
gLocationServiceStatus.locationStatus = kLocationServiceFailed;
gLocationServiceStatus.headingStatus = kLocationServiceFailed;
}
#end
I followed this link to extract the required values from the plugin but cant understand how it works.Plugin into unity
The code below is how I tried to get the latitudes and longitudes from plugin.I wrote a script and added a method
public class Getposition : MonoBehaviour {
#if UNITY_IOS
[DllImport("__Internal")]
********* // Here Which Method should I call?? I am calling from the plugin??
//I have to pass any values?? //*********
private static extern float UnitySetLastHeading(double timestamp,
float latitude,
float longitude,
float altitude,
float horizontalAccuracy,
float verticalAccuracy);
#endif
}
public getlatlonginfo( /*what all values required */)
{
//Get values from Plugin??
//string latitudevalues=?
//string longitudevalues=?
}
What I am trying to achieve is given below
Get the values that are picked up in iPhone_Sensors.mm, convert them into a string, and pass them into Unity
I am trying convert them to string so that I can get more decimal point and thus increase the accuracy.Not that expert with plugins.

There are two ways that I can think of.. First is to use a struct and return the coordinates directly.. The second is to register a callback/handler for when location does update.. You should really take a look at: https://www.mono-project.com/docs/advanced/pinvoke/
Anyway.. some code:
C++ side:
//Convert a C++ string to NSString
NSString* CPPStringToIOSString(const char* cppString)
{
return cppString ? [NSString stringWithUTF8String:cppString] : nullptr;
}
//Convert an NSString to C++ string.
const char* IOSStringToCPPString(NSString *iosString)
{
if ([iosString length])
{
const char* str = [iosString UTF8String];
if (str && strlen(str))
{
char* unityString = static_cast<char*>(malloc(strlen(str) + 1));
strcpy(unityString, str);
return unityString;
}
}
return nullptr;
}
static LocationServiceInfo GetLocationServiceInfo()
{
static LocationServiceInfo info;
return info;
}
//Exports:
extern "C" {
//When called, returns a CLLocationCoordinate2D to Unity.
CLLocationCoordinate2D _GetCoordinates()
{
CLLocationManager *manager = GetLocationServiceInfo().GetLocationManager();
return [manager getCurrentLocation];
}
//When called, registers a listen with LocationManager.
//The listener is called whenever the location has updated/changed.
void _RegisterLocationUpdateHandler(void(*callback)(double, double))
{
//Implement your own logic for this..
//Then call `callback` with the lat and lon.
GetLocationServiceInfo().onLocationDidUpdate = ^(double lat, double lon) {
if (callback) {
callback(lat, lon);
}
};
}
}
C# side (Plugin)..
//Struct representing coordinates received from the iOS plugin.
public struct CLLocationCoordinate2D {
double latitude;
double longitude;
}
//Imported function.
[DllImport ("__Internal")]
private static extern CLLocationCoordinate2D _GetCoordinates();
//Call the imported `GetCoordinates` when this function is called.
public static CLLocationCoordinate2D GetCoordinates()
{
return _GetCoordinates();
}
//------ Async ------
//Callback function pointer declaration..
public delegate void LocationCallbackFunc(double latitude, double longitude);
//Imported RegisterLocationUpdate function
[DllImport ("__Internal")]
private static extern void _RegisterLocationUpdateHandler(LocationCallback funcPtr);
//This function is called whenever location changed and has been updated via the iOS plugin..
private static void LocationDidChange(double latitude, double longitude)
{
Debug.Log(latitude);
Debug.Log(longitude);
}
//Call this function to register the location handler callback to be notified when location changes on the iOS side..
private static void RegisterLocationUpdateHandler()
{
_RegisterLocationUpdateHandler(new LocationCallbackFunc(this.LocationDidChange))
}

Related

EA Opens more orders than expected in MQL4

Everything seems fine. But EA usually opens multiple trades in the same second... The way I built it is very linear and i can't seem to spot the logical mistake. It is basically a random martingale EA to test stuff out. Any indicator (that's why I called it random, haven't decided myself) can be put in there.
Basic idea is that it has an upper and lower threshold which determines when it is in buy zone and when at sell zone. Once it is in either zone, if trend goes against it (determined by indicator's value, not symbol's price) it opens another trade with the same SL/TP of the initial order. Also it checks whether initial trade still runs so it does not open other ones and once the initial trade is open. After that the criterias about the rest of the trades (that go against the trade are different).
The problem is that it opens multiple trades at times that it shouldn't, or like 3-4 trades within the same second or two. Any idea why this happens?
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
input int stepValue = 5;
input double lotsize = 0.01;
input int stoploss = 2000;
input int takeprofit = 140;
input int slippage = 10;
input double upper_border = 60.0;
input double lower_border = 40.0;
const string EAComment = "Xind";
string mode = "";
bool first_trade = false;
int InitTicket = 1;
double X = 0.0;
double X_Last = 0.0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
first_trade = false;
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
SearchSignal();
if (mode == "Buy")
{
if (first_trade == false)
{
Buy();
}
if (first_trade == true)
{
MartinCheck();
CloseCheck();
}
}
if (mode == "Sell")
{
if (first_trade == false)
{
Sell();
}
if (first_trade == true)
{
MartinCheck();
CloseCheck();
}
}
}
//+------------------------------------------------------------------+
void Buy()
{
X_Last = X;
first_trade = true;
InitTicket = OrderSend(NULL,OP_BUY,lotsize,Ask,slippage,Ask-stoploss*Point,Ask+takeprofit*Point,EAComment,1,0,clrDarkBlue);
}
//---
void Sell()
{
X_Last = X;
first_trade = true;
InitTicket = OrderSend(NULL,OP_SELL,lotsize,Bid,slippage,Bid+stoploss*Point,Bid-takeprofit*Point,EAComment,1,0,clrDarkRed);
}
//---
void MartinBuy()
{
if (OrderSelect(InitTicket, SELECT_BY_TICKET) == true)
{
double new_SL = OrderStopLoss();
double new_TP = OrderTakeProfit();
int dont_care = OrderSend(NULL,OP_BUY,lotsize,Ask,slippage,new_SL,new_TP,EAComment+" martin",1,0,clrDarkBlue);
}
}
//---
void MartinSell()
{
if (OrderSelect(InitTicket, SELECT_BY_TICKET) == true)
{
double new_SL = OrderStopLoss();
double new_TP = OrderTakeProfit();
int dont_care = OrderSend(NULL,OP_SELL,lotsize,Bid,slippage,new_SL,new_TP,EAComment+" martin",1,0,clrDarkRed);
}
}
//---
void SearchSignal()
{
X = 0.0; //where 0.0, put here the iCustom for external indicators, or some built-in indicator
if (X >= upper_border)
{
mode = "Sell";
}
else if (X <= lower_border)
{
mode = "Buy";
}
else
{
mode = "";
first_trade = false;
InitTicket = 1;
X_Last = 0.0;
}
}
//---
void CloseCheck()
{
if (OrderSelect(InitTicket, SELECT_BY_TICKET))
{
if (OrderCloseTime() == 0)
{
first_trade = true;
}
else if (OrderCloseTime() != 0)
{
first_trade = false;
}
else
{
return;
}
}
}
//---
void MartinCheck()
{
if (mode == "Buy")
{
if ((X_Last - stepValue) >= X)
{
X_Last = X;
MartinBuy();
}
}
if (mode == "Sell")
{
if ((X_Last + stepValue) <= X)
{
X_Last = X;
MartinSell();
}
}
}
The layout of your code makes it possible for several processes to happen in sequence all on the same tick which I assume you do not want. Try changing your code initially to this and work from there:
void OnTick()
{
SearchSignal();
if(mode=="Buy")
{
if(!first_trade) Buy();
else
{
MartinCheck();
CloseCheck();
}
}
else if(mode=="Sell")
{
if(!first_trade) Sell();
else
{
MartinCheck();
CloseCheck();
}
}
}
Remember to use if(...) else to stop executing all functions when it should only be an either/or situation.

MQL4 How to call OnChartEvent() from init()

I want to call OnChartEvent() from init() like the code below, so the EA should process first the password and then the rest of the code.
I am just newbie not an expert in coding.
The idea or objective, the password must enter first and correctly, after successful then process the rest of code.
#include <ChartObjects/ChartObjectsTxtControls.mqh>
int init()
{
password_edit.Create(0, "password_edit", 0, 10, 10, 260, 25);
password_edit.BackColor(White);
password_edit.BorderColor(Black);
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent( const int id,
const long &lparam,
const double &dparam,
const string &sparam
)
{
//---
if (id == CHARTEVENT_OBJECT_ENDEDIT && sparam == "password_edit" )
{
password_status = -1;
for (int i=0; i<ArraySize(allowed_passwords); i++)
if (password_edit.GetString(OBJPROP_TEXT) == allowed_passwords[i])
{
password_status = i;
break;
}
if (password_status == -1)
{
password_edit.SetString(OBJPROP_TEXT, 0, password_message[0]);
ExpertRemove();
}
else
{
password_edit.SetString(OBJPROP_TEXT, 0, password_message[1]);
}
}
}
//+------------------------------------------------------------------+
int OnInit(){
passwordOperation();
return INIT_SUCCEED;
}
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
//---
if (id == CHARTEVENT_OBJECT_ENDEDIT && sparam == "password_edit" )
{
passwordOperation();
}
}
void passwordOperation()
{
password_status = -1;
for (int i=0; i<ArraySize(allowed_passwords); i++)
if (password_edit.GetString(OBJPROP_TEXT) == allowed_passwords[i])
{
password_status = i;
break;
}
if (password_status == -1)
{
password_edit.SetString(OBJPROP_TEXT, 0, password_message[0]);
ExpertRemove();
}
else
{
password_edit.SetString(OBJPROP_TEXT, 0, password_message[1]);
}
}

Use AudioQueue to play AAC, but the callback function doesn't work

Recently, my project wants to achieving audio communication by AAC, so i use the AudioQueue, but there is a problem that my player's callback function doesn't work, in my project the callback function has worked 3 times. that is for function work 3 times. and when active AudioQueueStart(mQueue, NULL), the callback function never be called.
I use two iPhone to run. they are connect by udp socket, and i'm sure this part is fine. i can get the correct audio data.
And i modify a demo which is play a file data not memory. so i don't know is it a problem?
here is my code: AQPlayer.h
#include <AudioToolbox/AudioToolbox.h>
#include "CAStreamBasicDescription.h"
#include "CAXException.h"
#define kNumberBuffers 3
#define kBufferDurationSeconds 0.5
class AQPlayer
{
public:
AQPlayer();
~AQPlayer();
OSStatus StartQueue(BOOL inResume);
OSStatus StopQueue();
OSStatus PauseQueue();
AudioQueueRef Queue() { return mQueue; }
CAStreamBasicDescription DataFormat() const { return mDataFormat; }
Boolean IsRunning() const { return (mIsRunning) ? true : false; }
Boolean IsInitialized() const { return mIsInitialized; }
CFStringRef GetFilePath() const { return (mFilePath) ? mFilePath : CFSTR(""); }
Boolean IsLooping() const { return mIsLooping; }
void SetLooping(Boolean inIsLooping) { mIsLooping = inIsLooping; }
void CreateQueueForFile(CFStringRef inFilePath);
void DisposeQueue(Boolean inDisposeFile);
void prepareAudioQueue();
void start();
void stop();
private:
UInt32 GetNumPacketsToRead() { return mNumPacketsToRead; }
SInt64 GetCurrentPacket() { return mCurrentPacket; }
AudioFileID GetAudioFileID() { return mAudioFile; }
void SetCurrentPacket(SInt64 inPacket) { mCurrentPacket = inPacket; }
void SetupNewQueue();
AudioQueueRef mQueue;
AudioQueueBufferRef mBuffers[kNumberBuffers];
AudioFileID mAudioFile;
CFStringRef mFilePath;
CAStreamBasicDescription mDataFormat;
Boolean mIsInitialized;
UInt32 mNumPacketsToRead;
SInt64 mCurrentPacket;
UInt32 mIsRunning;
Boolean mIsDone;
Boolean mIsLooping;
static void isRunningProc( void * inUserData,
AudioQueueRef inAQ,
AudioQueuePropertyID inID);
static void AQBufferCallback( void * inUserData,
AudioQueueRef inAQ,
AudioQueueBufferRef inCompleteAQBuffer);
void CalculateBytesForTime( CAStreamBasicDescription & inDesc,
UInt32 inMaxPacketSize,
Float64 inSeconds,
UInt32 *outBufferSize,
UInt32 *outNumPackets);
};
and here is AQPlayer.mm
#include "package.h"
#include "udpsocket.h"
#define MAXPACKETSIZE 1000
#define BUFFER_SIZE 4000
#include "AQPlayer.h"
extern udpsocket *udp;
void AQPlayer::AQBufferCallback(void * inUserData,
AudioQueueRef inAQ,
AudioQueueBufferRef inCompleteAQBuffer)
{
AQPlayer *THIS = (AQPlayer *)inUserData;
dispatch_semaphore_wait(udp->sempahore,DISPATCH_TIME_FOREVER);
NSLog(#"read begin");
while ([udp->AudioQueue count]>0 &&
![[udp->AudioQueue objectAtIndex:0] isKindOfClass:[AUDIO_CACHE_OBJECT class]])
{
[udp->AudioQueue removeObjectAtIndex:0];
}
if([udp->AudioQueue count]<1){
[NSThread sleepForTimeInterval:0.05];
AQBufferCallback(inUserData, inAQ, inCompleteAQBuffer);
return;
}
int packets = 0;
int dataLen = 0;
AUDIO_CACHE_OBJECT *pack;
char *data = (char*)malloc(sizeof(char)*BUFFER_SIZE);;
memset(data, 0, BUFFER_SIZE);
pack = [udp->AudioQueue firstObject];
while (dataLen+pack.datalen<BUFFER_SIZE && [udp->AudioQueue count]>0 /*&& packets<21*/) {
memcpy(data+dataLen, [pack GetData], [pack datalen]);
dataLen+=[pack datalen];
[udp->AudioQueue removeObjectAtIndex:0];
// [pack memset];
packets ++;
while ([udp->AudioQueue count]>1 &&
![[udp->AudioQueue objectAtIndex:0] isKindOfClass:[AUDIO_CACHE_OBJECT class]])
{
[udp->AudioQueue removeObjectAtIndex:0];
}
if([udp->AudioQueue count]<1){
break;
}
pack = [udp->AudioQueue firstObject];
}
memcpy(inCompleteAQBuffer->mAudioData, data, dataLen);
inCompleteAQBuffer->mAudioDataByteSize = dataLen;
inCompleteAQBuffer->mPacketDescriptionCount = packets;
AudioQueueEnqueueBuffer(inAQ, inCompleteAQBuffer, 0,NULL);
THIS->mCurrentPacket += packets;
free(data);
NSLog(#"read end --- %lld",THIS->mCurrentPacket);
}
void AQPlayer::isRunningProc ( void * inUserData,
AudioQueueRef inAQ,
AudioQueuePropertyID inID)
{
AQPlayer *THIS = (AQPlayer *)inUserData;
UInt32 size = sizeof(THIS->mIsRunning);
OSStatus result = AudioQueueGetProperty (inAQ, kAudioQueueProperty_IsRunning, &THIS->mIsRunning, &size);
if ((result == noErr) && (!THIS->mIsRunning))
[[NSNotificationCenter defaultCenter] postNotificationName: #"playbackQueueStopped" object: nil];
}
void AQPlayer::CalculateBytesForTime (CAStreamBasicDescription & inDesc, UInt32 inMaxPacketSize, Float64 inSeconds, UInt32 *outBufferSize, UInt32 *outNumPackets)
{
// we only use time here as a guideline
// we're really trying to get somewhere between 16K and 64K buffers, but not allocate too much if we don't need it
static const int maxBufferSize = 0x10000; // limit size to 64K
static const int minBufferSize = 0x4000; // limit size to 16K
if (inDesc.mFramesPerPacket) {
Float64 numPacketsForTime = inDesc.mSampleRate / inDesc.mFramesPerPacket * inSeconds;
*outBufferSize = numPacketsForTime * inMaxPacketSize;
} else {
// if frames per packet is zero, then the codec has no predictable packet == time
// so we can't tailor this (we don't know how many Packets represent a time period
// we'll just return a default buffer size
*outBufferSize = maxBufferSize > inMaxPacketSize ? maxBufferSize : inMaxPacketSize;
}
// we're going to limit our size to our default
if (*outBufferSize > maxBufferSize && *outBufferSize > inMaxPacketSize)
*outBufferSize = maxBufferSize;
else {
// also make sure we're not too small - we don't want to go the disk for too small chunks
if (*outBufferSize < minBufferSize)
*outBufferSize = minBufferSize;
}
*outNumPackets = *outBufferSize / inMaxPacketSize;
}
AQPlayer::AQPlayer() :
mQueue(0),
mAudioFile(0),
mFilePath(NULL),
mIsRunning(false),
mIsInitialized(false),
mNumPacketsToRead(0),
mCurrentPacket(0),
mIsDone(false),
mIsLooping(false) { }
AQPlayer::~AQPlayer()
{
DisposeQueue(true);
}
OSStatus AQPlayer::StartQueue(BOOL inResume)
{
if (mQueue == NULL)
CreateQueueForFile(mFilePath);
mIsDone = false;
if (!inResume)
mCurrentPacket = 0;
for (int i = 0; i < kNumberBuffers; ++i) {
AQBufferCallback (this, mQueue, mBuffers[i]);
}
NSLog(#"audioqueuestart");
UInt32 i =0;
AudioQueuePrime(mQueue, 0, &i);
NSLog(#"%d",(unsigned int)i);
return AudioQueueStart(mQueue, NULL);
}
OSStatus AQPlayer::StopQueue()
{
OSStatus result = AudioQueueStop(mQueue, true);
if (result) printf("ERROR STOPPING QUEUE!\n");
return result;
}
OSStatus AQPlayer::PauseQueue()
{
OSStatus result = AudioQueuePause(mQueue);
return result;
}
void AQPlayer::CreateQueueForFile(CFStringRef inFilePath)
{
try {
UInt32 size = sizeof(mDataFormat);
mDataFormat.mSampleRate = 44100;
mDataFormat.mFormatID = kAudioFormatMPEG4AAC;
mDataFormat.mFormatFlags = 0;
mDataFormat.mFramesPerPacket = 1024;
mDataFormat.mChannelsPerFrame = 2;
mDataFormat.mBitsPerChannel = 0;//表示这是一个压缩格式
mDataFormat.mBytesPerPacket = 0;//表示这是一个变比特率压缩
mDataFormat.mBytesPerFrame = 0;
mDataFormat.mReserved = 0;
//aqc.bufferByteSize = 2000;
SetupNewQueue();
}
catch (NSException *e) {
fprintf(stderr, "Error: %# (%#)\n", [e debugDescription], [e description]);
}
}
void AQPlayer::SetupNewQueue()
{
AudioQueueNewOutput(&mDataFormat, AQPlayer::AQBufferCallback, this,//NULL,NULL,0,&mQueue);
CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &mQueue);
UInt32 bufferByteSize;
UInt32 maxPacketSize = MAXPACKETSIZE;
UInt32 size = sizeof(maxPacketSize);
CalculateBytesForTime (mDataFormat, maxPacketSize, kBufferDurationSeconds, &bufferByteSize, &mNumPacketsToRead);
size = sizeof(UInt32);
AudioQueueAddPropertyListener(mQueue, kAudioQueueProperty_IsRunning, isRunningProc, this);
bool isFormatVBR = (mDataFormat.mBytesPerPacket == 0 || mDataFormat.mFramesPerPacket == 0);
AudioQueueSetParameter(mQueue, kAudioQueueParam_Volume, 1.0);
for (int i = 0; i < kNumberBuffers; ++i) {
AudioQueueAllocateBuffer(mQueue, bufferByteSize, &mBuffers[i]);
}
// set the volume of the queue
mIsInitialized = true;
}
void AQPlayer::DisposeQueue(Boolean inDisposeFile)
{
if (mQueue)
{
AudioQueueDispose(mQueue, true);
mQueue = NULL;
}
if (inDisposeFile)
{
if (mAudioFile)
{
AudioFileClose(mAudioFile);
mAudioFile = 0;
}
if (mFilePath)
{
CFRelease(mFilePath);
mFilePath = NULL;
}
}
mIsInitialized = false;
}
Thank for your time.
Your input is VBR so your buffers need an accompanying packet description array. Use AudioQueueAllocateBufferWithPacketDescriptions: instead of AudioQueueAllocateBuffer: when you are initially creating your buffers. Then set mStartOffset, mDataByteSize, and mVariableFramesInPacket (always zero) for each packet inside your while loop in your callback procedure.

how to write display driver

I am writing display drivers for micro oled.
board is dart4460 (omap4460) which provides dss(display subsystem).
so I am writing drivers using dss.
but I dont know what I wrote is right or not
oled display use dpi interface and i2c for commands
I referred to pico dlp projector driver source which uses dpi and i2c.
here are datasheets
dart4460: http://www.variscite.com/images/DART-4460-DS_107.pdf
micro oled display: https://www.dropbox.com/s/ixpws4qzo3ttj6e/SVGA050.pdf?dl=0
Code:
panel-svga.c
#define SLAVE_ADDR_READ 0x1F
#define SLAVW_ADDR_WRITE 0x1E
struct svga050_i2c_data {
struct mutex xfer_lock;
};
struct svga050_data {
struct i2c_client *client;
struct mutex lock;
};
static struct i2c_board_info svga050_i2c_board_info = {
I2C_BOARD_INFO("svga050_i2c_drive",SLAVE_ADDR_WRITE);
}
static struct omap_video_timings svga050_timings = {
.x_res = 800,
.y_res = 600,
.pixel_clock = 40000,
.hsw = 128,
.hfp = 40,
.hbp = 88,
.vsw = 4,
.vfp = 1,
.vbp = 23,
};
static int svga050_panel_power_on(struct omap_dss_device *dssdev)
{
int r;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
r = omapdss_dpi_display_enable(dssdev);
if (r)
goto err0;
if (dssdev->platform_enable) {
r = dssdev->platform_enable(dssdev);
if (r)
goto err1;
}
return 0;
err1:
omapdss_dpi_display_disable(dssdev);
err0:
return r;
}
static void svga050_panel_power_off(struct omap_dss_device *dssdev)
{
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return;
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
omapdss_dpi_display_disable(dssdev);
}
static inline struct svga050_panel_data *get_panel_data(const struct omap_dss_device *dssdev)
{
return (struct svga050_panel_data *)dssdev->data;
}
static int svga050_panel_probe(struct omap_dss_device *dssdev)
{
struct svga050_data *svga_data;
struct i2c_adapter *adapter;
struct i2c_client *svga_i2c_client;
struct svga050_panel_data *svga_pdata=get_panel_data(dssdev);
int r;
dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
OMAP_DSS_LCD_IHS;
dssdev->panel.timings = svga050_timings;
svga_data = devm_kzalloc(&dssdev->dev,sizeof(*svga_data), GFP_KERNEL);
if (!svga_data) {
r = -ENOMEM;
goto err;
}
mutex_init(&ld->lock);
dev_set_drvdata(&dssdev->dev, ld);
return 0;
err:
return r;
}
static void svga050_panel_remove(struct omap_dss_device *dssdev)
{
struct svga050_data *ld = dev_get_drvdata(&dssdev->dev);
kfree(ld);
}
static int svga050_panel_enable(struct omap_dss_device *dssdev)
{
struct svga050_data *ld = dev_get_drvdata(&dssdev->dev);
int r;
mutex_lock(&ld->lock);
r = svga050_panel_power_on(dssdev);
if (r)
goto err;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
mutex_unlock(&ld->lock);
return 0;
err:
mutex_unlock(&ld->lock);
return r;
}
static void svga050_panel_disable(struct omap_dss_device *dssdev)
{
struct svga050_data *ld = dev_get_drvdata(&dssdev->dev);
mutex_lock(&ld->lock);
svga050_panel_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
mutex_unlock(&ld->lock);
}
static int svga050_panel_suspend(struct omap_dss_device *dssdev)
{
struct svga050_data *ld = dev_get_drvdata(&dssdev->dev);
mutex_lock(&ld->lock);
svga050_panel_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
mutex_unlock(&ld->lock);
return 0;
}
static int svga050_panel_resume(struct omap_dss_device *dssdev)
{
struct svga050_data *ld = dev_get_drvdata(&dssdev->dev);
int r;
mutex_lock(&ld->lock);
r = svga050_panel_power_on(dssdev);
if (r)
goto err;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
mutex_unlock(&ld->lock);
return 0;
err:
mutex_unlock(&ld->lock);
return r;
}
static struct omap_dss_driver svga050_driver = {
.probe = svga050_panel_probe,
.remove = svga050_panel_remove,
.enable = svga050_panel_enable,
.disable = svga050_panel_disable,
.suspend = svga050_panel_suspend,
.resume = svga050_panel_resume,
.driver = {
.name = "svga050",
.owner = THIS_MODULE,
},
};
static int svga050_i2c_read(struct i2c_client *client, u8 reg)
{
u8 read_cmd[] = { SLAVE_ADDR_READ, reg }, data;
struct svga050_i2c_data *picodlp_i2c_data = i2c_get_clientdata(client);
struct i2c_msg msg[2];
mutex_lock(&svga050_i2c_data->xfer_lock);
msg[0].addr = client->addr;
msg[0].flags = 0;
msg[0].len = 2;
msg[0].buf = read_cmd;
msg[1].addr = client->addr;
msg[1].flags = I2C_M_RD;
msg[1].len = 2;
msg[1].buf = data;
i2c_transfer(client->adapter, msg, 2);
mutex_unlock(&svga050_i2c_data->xfer_lock);
return data;
}
static int svga050_i2c_write(struct i2c_client *client, u8 reg, u8 value)
{
u8 data[2];
int i;
struct i2c_msg msg;
int i, r, msg_count = 1;
struct svga050_i2c_data *picodlp_i2c_data = i2c_get_clientdata(client);
data[0] = reg;
data[1] = value;
mutex_lock(&svga050_i2c_data->xfer_lock);
msg.addr = client->addr;
msg.flags = 0;
msg.len = 2;
msg.buf = data;
r = i2c_transfer(client->adapter, &msg, msg_count);
mutex_unlock(&svga050_i2c_data->xfer_lock);
/*
* i2c_transfer returns:
* number of messages sent in case of success
* a negative error number in case of failure
*/
if (r != msg_count)
goto err;
/* In case of success */
for (i = 0; i < 2; i++)
dev_dbg(&client->dev,
"addr %x bw 0x%02x[%d]: 0x%02x\n",
client->addr, data[0] + i, i, data[i]);
return 0;
err:
dev_err(&client->dev, "svga050_i2c_write error\n");
return r;
}
static int svga050_i2c_write_array(struct i2c_client *client,
const struct svga050_i2c_command commands[],
int count)
{
int i, r = 0;
for (i = 0; i < count; i++) {
r = svga050_i2c_write(client, commands[i].reg,
commands[i].value);
if (r)
return r;
}
return r;
}
static void init_svga050_panel(struct spi_device *spi)
{
}
static int __devinit svga050_panel_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
struct svga050_i2c_data *svga_i2c_data;
svga_i2c_data=kzalloc(sizeof(struct svga050_i2c_data),GFP_KERNEL);
if(svga_i2c_data == NULL)
return -ENOMEM;
i2c_set_clientdata(client,svga_i2c_data);
mutex_init(&svga_i2c_data->xfer_lock);
dev_err(&client->dev,"svga i2c initialized\n");
return 0;
}
static int __devexit svga050_panel_i2c_remove(struct i2c_client *client)
{
struct svga050_i2c_data *sd1= i2c_get_clientdata(client);
i2c_set_clientdata(client,NULL);
kfree(sd1);
return 0;
}
static const struct i2c_device_id svga050_i2c_idtable[]={
{"svga050_i2c_driver",0},
{},
};
static struct i2c_driver svga050_i2c_driver = {
.driver = {
.name = "svga050_i2c",
.owner = THIS_MODULE,
},
.probe = svga050_panel_i2c_probe,
.remove = __exit_p(svga050_panel_i2c_remove),
.id_table = svga050_i2c_idtable,
};
static int __init svga050_panel_drv_init(void)
{
int r;
r= i2c_add_driver(&svga050_i2c_driver);
if(r < 0){
printk(KERN_WARNING "svga050 i2c driver registration failed\n");
return r;
}
r=omap_dss_register_driver(&svga050_driver);
if(r < 0){
printk(KERN_WARNING "svga050 dss driver registration failed\n");
i2c_del_driver(&svga050_i2c_driver);
}
return r;
}
static void __exit svga050_panel_drv_exit(void)
{
omap_dss_unregister_driver(&svga050_driver);
i2c_del_driver(&svga050_i2c_driver);
}
module_init(svga050_panel_drv_init);
module_exit(svga050_panel_drv_exit);
MODULE_LICENSE("GPL");
Board.c
static struct omap_dss_device svga050_device = {
.name = "svga050",
.driver_name = "svga050",
.type = OMAP_DISPLAY_TYPE_DPI,
.phy.dpi.data_lines = 24,
.channel = OMAP_DSS_CHANNEL_LCD2,
.platform_enable = svga050_panel_enable_picodlp,
.platform_disable = svga050_panel_disable_picodlp,
.data = &svga050_pdata,
};
static struct omap_dss_device *svga050_dss_devices[] = {
&svga050_device,
};
static struct picodlp_panel_data sdp4430_picodlp_pdata = {
.svga050_adapter_id = 2,
};
my questions are :
My code is right?
I don't know how to write display init code by seeing datasheet.
Can I write display init code by seeing this datasheet ?
In panel_probe function, how can I get adapter ID ?
how do I choose adapter I ?
Is it right that I should write only i2c slave driver code in panel code ?
How can I select I2C master ? I want to use I2C3 or I2C4 for display commands

How to write XCTestCase for asynchronized method?

I'm working on a unit test for one of my model which is using asynchronized call to my rest api.The method used to request my API is like this:
requestOnComplete:(void(^)())complete onError:(void(^)(NSString* errMsg))fail;
In my test case:
-(void)testMyApiCall
{
[myObj requestOnComplete:^{
XCTAssertTrue(YES,#"Success");
} onError:^(NSString *errorString) {
XCTFail(#"Failed.%#", errorString);
}];
}
As I expected, this test always pass because of the asynchronized call. Can anybody advise on this issue? Thanks.
You can use lib XCAsyncTestCase
It simple to do XCTestCas asynchronized method.
Ex as your test function here is your code:
-(void)testMyApiCall
{
[myObj requestOnComplete:^{
[self notify:XCTestAsyncTestCaseStatusSucceeded];
} onError:^(NSString *errorString) {
[self notify:XCTestAsyncTestCaseStatusFailed];
}];
[self waitForStatus:XCTestAsyncTestCaseStatusSucceeded timeout:10];
}
I use these helper functions
BOOL XLCRunloopRunUntil(CFTimeInterval timeout, BOOL (^condition)(void));
#define XLCAssertTrueBeforeTimeout(expr, timeout, format...) \
XCTAssertTrue( (XLCRunloopRunUntil(timeout, ^BOOL{ return expr; })) , ## format )
static inline void XLCRunloopRunOnce()
{
while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001, YES) == kCFRunLoopRunHandledSource ||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, YES) == kCFRunLoopRunHandledSource);
}
static inline void XLCRunloopRun(CFTimeInterval timeout)
{
CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeout, NO);
XLCRunloopRunOnce();
}
BOOL XLCRunloopRunUntil(CFTimeInterval timeout, BOOL (^condition)(void)) {
static mach_timebase_info_data_t timebaseInfo;
if ( timebaseInfo.denom == 0 ) {
mach_timebase_info(&timebaseInfo);
}
uint64_t timeoutNano = timeout * 1e9;
uint64_t start = mach_absolute_time();
do {
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.01, YES);
XLCRunloopRunOnce();
uint64_t end = mach_absolute_time();
uint64_t elapsed = end - start;
uint64_t elapseNano = elapsed * timebaseInfo.numer / timebaseInfo.denom;
if (elapseNano >= timeoutNano) {
return NO;
}
} while (!condition());
return YES;
}
example
-(void)testMyApiCall
{
__block BOOL done = NO;
[myObj requestOnComplete:^{
// XCTAssertTrue(YES,#"Success"); // this line is pointless
done = YES;
} onError:^(NSString *errorString) {
XCTFail(#"Failed.%#", errorString);
done = YES;
}];
XLCAssertTrueBeforeTimeout(done, 1, "should finish within 1 seconds");
}

Resources