Initial commit
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// ESPTouchDelegate.h
|
||||
// EspTouchDemo
|
||||
//
|
||||
// Created by 白 桦 on 8/14/15.
|
||||
// Copyright (c) 2015 白 桦. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ESPTouchResult.h"
|
||||
|
||||
|
||||
@protocol ESPTouchDelegate <NSObject>
|
||||
|
||||
/**
|
||||
* when new esptouch result is added, the listener will call
|
||||
* onEsptouchResultAdded callback
|
||||
*
|
||||
* @param result
|
||||
* the Esptouch result
|
||||
*/
|
||||
-(void) onEsptouchResultAddedWithResult: (ESPTouchResult *) result;
|
||||
|
||||
@end
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// ESPTouchResult.h
|
||||
// EspTouchDemo
|
||||
//
|
||||
// Created by 白 桦 on 4/14/15.
|
||||
// Copyright (c) 2015 白 桦. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface ESPTouchResult : NSObject
|
||||
|
||||
// it is used to check whether the esptouch task is executed suc
|
||||
@property (nonatomic,assign) BOOL isSuc;
|
||||
|
||||
// it is used to store the device's bssid
|
||||
@property (nonatomic,strong) NSString * bssid;
|
||||
|
||||
// it is used to check whether the esptouch task is cancelled by user
|
||||
@property (atomic,assign) BOOL isCancelled;
|
||||
|
||||
// it is used to store the device's ip address
|
||||
@property (atomic) NSData * ipAddrData;
|
||||
|
||||
/**
|
||||
* Constructor of EsptouchResult
|
||||
*
|
||||
* @param isSuc whether the esptouch task is executed suc
|
||||
* @param bssid the device's bssid
|
||||
* @param ipAddrData the device's ip address
|
||||
*/
|
||||
- (id) initWithIsSuc: (BOOL) isSuc andBssid: (NSString *) bssid andInetAddrData: (NSData *) ipAddrData;
|
||||
|
||||
@end
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// ESPTouchResult.m
|
||||
// EspTouchDemo
|
||||
//
|
||||
// Created by 白 桦 on 4/14/15.
|
||||
// Copyright (c) 2015 白 桦. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ESPTouchResult.h"
|
||||
#import "ESP_NetUtil.h"
|
||||
|
||||
@implementation ESPTouchResult
|
||||
|
||||
- (id) initWithIsSuc: (BOOL) isSuc andBssid: (NSString *) bssid andInetAddrData: (NSData *) ipAddrData
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
self.isSuc = isSuc;
|
||||
self.bssid = bssid;
|
||||
self.isCancelled = NO;
|
||||
self.ipAddrData = ipAddrData;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
NSString *ipAddrDataStr = [ESP_NetUtil descriptionInetAddrByData:self.ipAddrData];
|
||||
return [[NSString alloc]initWithFormat:@"[isSuc: %@,isCancelled: %@,bssid: %@,inetAddress: %@]",self.isSuc? @"YES":@"NO",
|
||||
self.isCancelled? @"YES":@"NO"
|
||||
,self.bssid
|
||||
,ipAddrDataStr];
|
||||
}
|
||||
|
||||
@end
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
//
|
||||
// ESPTouchTask.h
|
||||
// EspTouchDemo
|
||||
//
|
||||
// Created by 白 桦 on 4/14/15.
|
||||
// Copyright (c) 2015 白 桦. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ESPTouchResult.h"
|
||||
#import "ESPTouchDelegate.h"
|
||||
|
||||
#define DEBUG_ON YES
|
||||
|
||||
@interface ESPTouchTask : NSObject
|
||||
|
||||
@property (atomic,assign) BOOL isCancelled;
|
||||
|
||||
/**
|
||||
* Constructor of EsptouchTask
|
||||
*
|
||||
* @param apSsid
|
||||
* the Ap's ssid
|
||||
* @param apBssid
|
||||
* the Ap's bssid
|
||||
* @param apPassword
|
||||
* the Ap's password
|
||||
* @param isSsidHidden
|
||||
* whether the Ap's ssid is hidden
|
||||
*/
|
||||
- (id) initWithApSsid: (NSString *)apSsid andApBssid: (NSString *) apBssid andApPwd: (NSString *)apPwd andIsSsidHiden: (BOOL) isSsidHidden;
|
||||
|
||||
/**
|
||||
* Constructor of EsptouchTask
|
||||
*
|
||||
* @param apSsid
|
||||
* the Ap's ssid
|
||||
* @param apBssid
|
||||
* the Ap's bssid
|
||||
* @param apPassword
|
||||
* the Ap's password
|
||||
* @param isSsidHidden
|
||||
* whether the Ap's ssid is hidden
|
||||
* @param timeoutMillisecond(it should be >= 15000+6000)
|
||||
* millisecond of total timeout
|
||||
* @param context
|
||||
* the Context of the Application
|
||||
*/
|
||||
- (id) initWithApSsid: (NSString *)apSsid andApBssid: (NSString *) apBssid andApPwd: (NSString *)apPwd andIsSsidHiden: (BOOL) isSsidHidden andTimeoutMillisecond: (int) timeoutMillisecond;
|
||||
|
||||
/**
|
||||
* Interrupt the Esptouch Task when User tap back or close the Application.
|
||||
*/
|
||||
|
||||
- (void) interrupt;
|
||||
|
||||
/**
|
||||
* Note: !!!Don't call the task at UI Main Thread
|
||||
*
|
||||
* Smart Config v2.4 support the API
|
||||
*
|
||||
* @return the ESPTouchResult
|
||||
*/
|
||||
- (ESPTouchResult*) executeForResult;
|
||||
|
||||
/**
|
||||
* Note: !!!Don't call the task at UI Main Thread
|
||||
*
|
||||
* Smart Config v2.4 support the API
|
||||
*
|
||||
* It will be blocked until the client receive result count >= expectTaskResultCount.
|
||||
* If it fail, it will return one fail result will be returned in the list.
|
||||
* If it is cancelled while executing,
|
||||
* if it has received some results, all of them will be returned in the list.
|
||||
* if it hasn't received any results, one cancel result will be returned in the list.
|
||||
*
|
||||
* @param expectTaskResultCount
|
||||
* the expect result count(if expectTaskResultCount <= 0,
|
||||
* expectTaskResultCount = INT32_MAX)
|
||||
* @return the NSArray of EsptouchResult
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
- (NSArray*) executeForResults:(int) expectTaskResultCount;
|
||||
|
||||
/**
|
||||
* set the esptouch delegate, when one device is connected to the Ap, it will be called back
|
||||
* @param esptouchDelegate when one device is connected to the Ap, it will be called back
|
||||
*/
|
||||
- (void) setEsptouchDelegate: (NSObject<ESPTouchDelegate> *) esptouchDelegate;
|
||||
|
||||
@end
|
||||
+467
@@ -0,0 +1,467 @@
|
||||
//
|
||||
// ESPTouchTask.m
|
||||
// EspTouchDemo
|
||||
//
|
||||
// Created by 白 桦 on 4/14/15.
|
||||
// Copyright (c) 2015 白 桦. All rights reserved.
|
||||
//
|
||||
|
||||
// The usage of NSCondition refer to: https://gist.github.com/prachigauriar/8118909
|
||||
|
||||
#import "ESPTouchTask.h"
|
||||
#import "ESP_ByteUtil.h"
|
||||
#import "ESPTouchGenerator.h"
|
||||
#import "ESPUDPSocketClient.h"
|
||||
#import "ESPUDPSocketServer.h"
|
||||
#import "ESP_NetUtil.h"
|
||||
#import "ESPTouchTaskParameter.h"
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#define ONE_DATA_LEN 3
|
||||
|
||||
@interface ESPTouchTask ()
|
||||
|
||||
@property (nonatomic,strong) NSString *_apSsid;
|
||||
|
||||
@property (nonatomic,strong) NSString *_apBssid;
|
||||
|
||||
@property (nonatomic,strong) NSString *_apPwd;
|
||||
|
||||
@property (atomic,assign) BOOL _isSuc;
|
||||
|
||||
@property (atomic,assign) BOOL _isInterrupt;
|
||||
|
||||
@property (nonatomic,strong) ESPUDPSocketClient *_client;
|
||||
|
||||
@property (nonatomic,strong) ESPUDPSocketServer *_server;
|
||||
|
||||
@property (atomic,strong) NSMutableArray *_esptouchResultArray;
|
||||
|
||||
@property (atomic,strong) NSCondition *_condition;
|
||||
|
||||
@property (nonatomic,assign) __block BOOL _isWakeUp;
|
||||
|
||||
@property (nonatomic,assign) volatile BOOL _isExecutedAlready;
|
||||
|
||||
@property (nonatomic,assign) BOOL _isSsidHidden;
|
||||
|
||||
@property (nonatomic,strong) ESPTaskParameter *_parameter;
|
||||
|
||||
@property (atomic,strong) NSMutableDictionary *_bssidTaskSucCountDict;
|
||||
|
||||
@property (atomic,strong) NSCondition *_esptouchResultArrayCondition;
|
||||
|
||||
@property (nonatomic,assign) __block UIBackgroundTaskIdentifier _backgroundTask;
|
||||
|
||||
@property (nonatomic,strong) id<ESPTouchDelegate> _esptouchDelegate;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ESPTouchTask
|
||||
|
||||
- (id) initWithApSsid: (NSString *)apSsid andApBssid: (NSString *) apBssid andApPwd: (NSString *)apPwd andIsSsidHiden: (BOOL) isSsidHidden
|
||||
{
|
||||
if (apSsid==nil||[apSsid isEqualToString:@""])
|
||||
{
|
||||
perror("ESPTouchTask initWithApSsid() apSsid shouldn't be null or empty");
|
||||
}
|
||||
// the apSsid should be null or empty
|
||||
assert(apSsid!=nil&&![apSsid isEqualToString:@""]);
|
||||
if (apPwd == nil)
|
||||
{
|
||||
apPwd = @"";
|
||||
}
|
||||
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask init");
|
||||
}
|
||||
self._apSsid = apSsid;
|
||||
self._apPwd = apPwd;
|
||||
self._apBssid = apBssid;
|
||||
self._parameter = [[ESPTaskParameter alloc]init];
|
||||
self._client = [[ESPUDPSocketClient alloc]init];
|
||||
self._server = [[ESPUDPSocketServer alloc]initWithPort: [self._parameter getPortListening]
|
||||
AndSocketTimeout: [self._parameter getWaitUdpTotalMillisecond]];
|
||||
self._isSuc = NO;
|
||||
self._isInterrupt = NO;
|
||||
self._isWakeUp = NO;
|
||||
self._isExecutedAlready = NO;
|
||||
self._condition = [[NSCondition alloc]init];
|
||||
self._isSsidHidden = isSsidHidden;
|
||||
self._esptouchResultArray = [[NSMutableArray alloc]init];
|
||||
self._bssidTaskSucCountDict = [[NSMutableDictionary alloc]init];
|
||||
self._esptouchResultArrayCondition = [[NSCondition alloc]init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id) initWithApSsid: (NSString *)apSsid andApBssid: (NSString *) apBssid andApPwd: (NSString *)apPwd andIsSsidHiden: (BOOL) isSsidHidden andTimeoutMillisecond: (int) timeoutMillisecond
|
||||
{
|
||||
ESPTouchTask *_self = [self initWithApSsid:apSsid andApBssid:apBssid andApPwd:apPwd andIsSsidHiden:isSsidHidden];
|
||||
if (_self)
|
||||
{
|
||||
[_self._parameter setWaitUdpTotalMillisecond:timeoutMillisecond];
|
||||
}
|
||||
return _self;
|
||||
}
|
||||
|
||||
- (void) __putEsptouchResultIsSuc: (BOOL) isSuc AndBssid: (NSString *)bssid AndInetAddr:(NSData *)inetAddr
|
||||
{
|
||||
[self._esptouchResultArrayCondition lock];
|
||||
// check whether the result receive enough UDP response
|
||||
BOOL isTaskSucCountEnough = NO;
|
||||
NSNumber *countNumber = [self._bssidTaskSucCountDict objectForKey:bssid];
|
||||
int count = 0;
|
||||
if (countNumber != nil)
|
||||
{
|
||||
count = [countNumber intValue];
|
||||
}
|
||||
++count;
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask __putEsptouchResult(): count = %d",count);
|
||||
}
|
||||
countNumber = [[NSNumber alloc]initWithInt:count];
|
||||
[self._bssidTaskSucCountDict setObject:countNumber forKey:bssid];
|
||||
isTaskSucCountEnough = count >= [self._parameter getThresholdSucBroadcastCount];
|
||||
if (!isTaskSucCountEnough)
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask __putEsptouchResult(): count = %d, isn't enough", count);
|
||||
}
|
||||
[self._esptouchResultArrayCondition unlock];
|
||||
return;
|
||||
}
|
||||
// check whether the result is in the mEsptouchResultList already
|
||||
BOOL isExist = NO;
|
||||
for (id esptouchResultId in self._esptouchResultArray)
|
||||
{
|
||||
ESPTouchResult *esptouchResultInArray = esptouchResultId;
|
||||
if ([esptouchResultInArray.bssid isEqualToString:bssid])
|
||||
{
|
||||
isExist = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// only add the result who isn't in the mEsptouchResultList
|
||||
if (!isExist)
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask __putEsptouchResult(): put one more result");
|
||||
}
|
||||
ESPTouchResult *esptouchResult = [[ESPTouchResult alloc]initWithIsSuc:isSuc andBssid:bssid andInetAddrData:inetAddr];
|
||||
[self._esptouchResultArray addObject:esptouchResult];
|
||||
if (self._esptouchDelegate != nil)
|
||||
{
|
||||
[self._esptouchDelegate onEsptouchResultAddedWithResult:esptouchResult];
|
||||
}
|
||||
}
|
||||
[self._esptouchResultArrayCondition unlock];
|
||||
}
|
||||
|
||||
-(NSArray *) __getEsptouchResultList
|
||||
{
|
||||
[self._esptouchResultArrayCondition lock];
|
||||
if ([self._esptouchResultArray count] == 0)
|
||||
{
|
||||
ESPTouchResult *esptouchResult = [[ESPTouchResult alloc]initWithIsSuc:NO andBssid:nil andInetAddrData:nil];
|
||||
esptouchResult.isCancelled = self.isCancelled;
|
||||
[self._esptouchResultArray addObject:esptouchResult];
|
||||
}
|
||||
|
||||
[self._esptouchResultArrayCondition unlock];
|
||||
return self._esptouchResultArray;
|
||||
|
||||
}
|
||||
|
||||
|
||||
- (void) beginBackgroundTask
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask beginBackgroundTask() entrance");
|
||||
}
|
||||
self._backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask beginBackgroundTask() endBackgroundTask");
|
||||
}
|
||||
[self endBackgroundTask];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void) endBackgroundTask
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask endBackgroundTask() entrance");
|
||||
}
|
||||
[[UIApplication sharedApplication] endBackgroundTask: self._backgroundTask];
|
||||
self._backgroundTask = UIBackgroundTaskInvalid;
|
||||
}
|
||||
|
||||
- (void) __listenAsyn: (const int) expectDataLen
|
||||
{
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||
dispatch_async(queue, ^{
|
||||
[self beginBackgroundTask];
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask __listenAsyn() start an asyn listen task, current thread is: %@", [NSThread currentThread]);
|
||||
}
|
||||
NSTimeInterval startTimestamp = [[NSDate date] timeIntervalSince1970];
|
||||
NSString *apSsidAndPwd = [NSString stringWithFormat:@"%@%@",self._apSsid,self._apPwd];
|
||||
Byte expectOneByte = [ESP_ByteUtil getBytesByNSString:apSsidAndPwd].length + 9;
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask __listenAsyn() expectOneByte: %d",expectOneByte);
|
||||
}
|
||||
Byte receiveOneByte = -1;
|
||||
NSData *receiveData = nil;
|
||||
while ([self._esptouchResultArray count] < [self._parameter getExpectTaskResultCount] && !self._isInterrupt)
|
||||
{
|
||||
receiveData = [self._server receiveSpecLenBytes:expectDataLen];
|
||||
if (receiveData != nil)
|
||||
{
|
||||
[receiveData getBytes:&receiveOneByte length:1];
|
||||
}
|
||||
else
|
||||
{
|
||||
receiveOneByte = -1;
|
||||
}
|
||||
if (receiveOneByte == expectOneByte)
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask __listenAsyn() receive correct broadcast");
|
||||
}
|
||||
// change the socket's timeout
|
||||
NSTimeInterval consume = [[NSDate date] timeIntervalSince1970] - startTimestamp;
|
||||
int timeout = (int)([self._parameter getWaitUdpTotalMillisecond] - consume*1000);
|
||||
if (timeout < 0)
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask __listenAsyn() esptouch timeout");
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask __listenAsyn() socketServer's new timeout is %d milliseconds",timeout);
|
||||
}
|
||||
[self._server setSocketTimeout:timeout];
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask __listenAsyn() receive correct broadcast");
|
||||
}
|
||||
if (receiveData != nil)
|
||||
{
|
||||
NSString *bssid =
|
||||
[ESP_ByteUtil parseBssid:(Byte *)[receiveData bytes]
|
||||
Offset:[self._parameter getEsptouchResultOneLen]
|
||||
Count:[self._parameter getEsptouchResultMacLen]];
|
||||
NSData *inetAddrData =
|
||||
[ESP_NetUtil parseInetAddrByData:receiveData
|
||||
andOffset:[self._parameter getEsptouchResultOneLen] + [self._parameter getEsptouchResultMacLen]
|
||||
andCount:[self._parameter getEsptouchResultIpLen]];
|
||||
[self __putEsptouchResultIsSuc:YES AndBssid:bssid AndInetAddr:inetAddrData];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask __listenAsyn() receive rubbish message, just ignore");
|
||||
}
|
||||
}
|
||||
}
|
||||
self._isSuc = [self._esptouchResultArray count] >= [self._parameter getExpectTaskResultCount];
|
||||
[self __interrupt];
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask __listenAsyn() finish");
|
||||
}
|
||||
[self endBackgroundTask];
|
||||
});
|
||||
}
|
||||
|
||||
- (void) interrupt
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask interrupt()");
|
||||
}
|
||||
self.isCancelled = YES;
|
||||
[self __interrupt];
|
||||
}
|
||||
|
||||
- (void) __interrupt
|
||||
{
|
||||
self._isInterrupt = YES;
|
||||
[self._client interrupt];
|
||||
[self._server interrupt];
|
||||
// notify the ESPTouchTask to wake up from sleep mode
|
||||
[self __notify];
|
||||
}
|
||||
|
||||
- (BOOL) __execute: (ESPTouchGenerator *)generator
|
||||
{
|
||||
NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970];
|
||||
NSTimeInterval currentTime = startTime;
|
||||
NSTimeInterval lastTime = currentTime - [self._parameter getTimeoutTotalCodeMillisecond];
|
||||
|
||||
NSArray *gcBytes2 = [generator getGCBytes2];
|
||||
NSArray *dcBytes2 = [generator getDCBytes2];
|
||||
|
||||
int index = 0;
|
||||
|
||||
while (!self._isInterrupt)
|
||||
{
|
||||
if (currentTime - lastTime >= [self._parameter getTimeoutTotalCodeMillisecond]/1000.0)
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask __execute() send gc code ");
|
||||
}
|
||||
// send guide code
|
||||
while (!self._isInterrupt && [[NSDate date] timeIntervalSince1970] - currentTime < [self._parameter getTimeoutGuideCodeMillisecond]/1000.0)
|
||||
{
|
||||
[self._client sendDataWithBytesArray2:gcBytes2
|
||||
ToTargetHostName:[self._parameter getTargetHostname]
|
||||
WithPort:[self._parameter getTargetPort]
|
||||
andInterval:[self._parameter getIntervalGuideCodeMillisecond]];
|
||||
// check whether the udp is send enough time
|
||||
if ([[NSDate date] timeIntervalSince1970] - startTime > [self._parameter getWaitUdpSendingMillisecond]/1000.0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
lastTime = currentTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self._client sendDataWithBytesArray2:dcBytes2
|
||||
Offset:index
|
||||
Count:ONE_DATA_LEN
|
||||
ToTargetHostName:[self._parameter getTargetHostname]
|
||||
WithPort:[self._parameter getTargetPort]
|
||||
andInterval:[self._parameter getIntervalDataCodeMillisecond]];
|
||||
index = (index + ONE_DATA_LEN) % [dcBytes2 count];
|
||||
}
|
||||
currentTime = [[NSDate date] timeIntervalSince1970];
|
||||
// check whether the udp is send enough time
|
||||
if ([[NSDate date] timeIntervalSince1970] - startTime > [self._parameter getWaitUdpSendingMillisecond]/1000.0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return self._isSuc;
|
||||
}
|
||||
|
||||
- (void) __checkTaskValid
|
||||
{
|
||||
if (self._isExecutedAlready)
|
||||
{
|
||||
perror("ESPTouchTask __checkTaskValid() fail, the task could be executed only once");
|
||||
}
|
||||
// !!!NOTE: the esptouch task could be executed only once
|
||||
assert(!self._isExecutedAlready);
|
||||
self._isExecutedAlready = YES;
|
||||
}
|
||||
|
||||
- (ESPTouchResult *) executeForResult
|
||||
{
|
||||
return [[self executeForResults:1] objectAtIndex:0];
|
||||
}
|
||||
|
||||
- (NSArray*) executeForResults:(int) expectTaskResultCount
|
||||
{
|
||||
// set task result count
|
||||
if (expectTaskResultCount <= 0)
|
||||
{
|
||||
expectTaskResultCount = INT32_MAX;
|
||||
}
|
||||
[self._parameter setExpectTaskResultCount:expectTaskResultCount];
|
||||
|
||||
[self __checkTaskValid];
|
||||
|
||||
NSData *localInetAddrData = [ESP_NetUtil getLocalInetAddress];
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask executeForResult() localInetAddr: %@", [ESP_NetUtil descriptionInetAddrByData:localInetAddrData]);
|
||||
}
|
||||
// generator the esptouch byte[][] to be transformed, which will cost
|
||||
// some time(maybe a bit much)
|
||||
ESPTouchGenerator *generator = [[ESPTouchGenerator alloc]initWithSsid:self._apSsid andApBssid:self._apBssid andApPassword:self._apPwd andInetAddrData:localInetAddrData andIsSsidHidden:self._isSsidHidden];
|
||||
// listen the esptouch result asyn
|
||||
[self __listenAsyn:[self._parameter getEsptouchResultTotalLen]];
|
||||
BOOL isSuc = NO;
|
||||
for (int i = 0; i < [self._parameter getTotalRepeatTime]; i++)
|
||||
{
|
||||
isSuc = [self __execute:generator];
|
||||
if (isSuc)
|
||||
{
|
||||
return [self __getEsptouchResultList];
|
||||
}
|
||||
}
|
||||
|
||||
if (!self._isInterrupt)
|
||||
{
|
||||
[self __sleep: [self._parameter getWaitUdpReceivingMillisecond]];
|
||||
[self __interrupt];
|
||||
}
|
||||
|
||||
return [self __getEsptouchResultList];
|
||||
}
|
||||
|
||||
// sleep some milliseconds
|
||||
- (BOOL) __sleep :(long) milliseconds
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask __sleep() start");
|
||||
}
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSinceNow: milliseconds/1000.0];
|
||||
[self._condition lock];
|
||||
BOOL signaled = NO;
|
||||
while (!self._isWakeUp && (signaled = [self._condition waitUntilDate:date]))
|
||||
{
|
||||
}
|
||||
[self._condition unlock];
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask __sleep() end, receive signal is %@", signaled ? @"YES" : @"NO");
|
||||
}
|
||||
return signaled;
|
||||
}
|
||||
|
||||
// notify the sleep thread to wake up
|
||||
- (void) __notify
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"ESPTouchTask __notify()");
|
||||
}
|
||||
[self._condition lock];
|
||||
self._isWakeUp = YES;
|
||||
[self._condition signal];
|
||||
[self._condition unlock];
|
||||
}
|
||||
|
||||
- (void) setEsptouchDelegate: (NSObject<ESPTouchDelegate> *) esptouchDelegate
|
||||
{
|
||||
self._esptouchDelegate = esptouchDelegate;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,139 @@
|
||||
//
|
||||
// ESPTaskParameter.h
|
||||
// EspTouchDemo
|
||||
//
|
||||
// Created by 白 桦 on 5/20/15.
|
||||
// Copyright (c) 2015 白 桦. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface ESPTaskParameter : NSObject
|
||||
|
||||
/**
|
||||
* get interval millisecond for guide code(the time between each guide code sending)
|
||||
* @return interval millisecond for guide code(the time between each guide code sending)
|
||||
*/
|
||||
- (long) getIntervalGuideCodeMillisecond;
|
||||
|
||||
/**
|
||||
* get interval millisecond for data code(the time between each data code sending)
|
||||
* @return interval millisecond for data code(the time between each data code sending)
|
||||
*/
|
||||
- (long) getIntervalDataCodeMillisecond;
|
||||
|
||||
/**
|
||||
* get timeout millisecond for guide code(the time how much the guide code sending)
|
||||
* @return timeout millisecond for guide code(the time how much the guide code sending)
|
||||
*/
|
||||
- (long) getTimeoutGuideCodeMillisecond;
|
||||
|
||||
/**
|
||||
* get timeout millisecond for data code(the time how much the data code sending)
|
||||
* @return timeout millisecond for data code(the time how much the data code sending)
|
||||
*/
|
||||
- (long) getTimeoutDataCodeMillisecond;
|
||||
|
||||
/**
|
||||
* get timeout millisecond for total code(guide code and data code altogether)
|
||||
* @return timeout millisecond for total code(guide code and data code altogether)
|
||||
*/
|
||||
- (long) getTimeoutTotalCodeMillisecond;
|
||||
|
||||
/**
|
||||
* get total repeat time for executing esptouch task
|
||||
* @return total repeat time for executing esptouch task
|
||||
*/
|
||||
- (int) getTotalRepeatTime;
|
||||
|
||||
/**
|
||||
* the length of the Esptouch result 1st byte is the total length of ssid and
|
||||
* password, the other 6 bytes are the device's bssid
|
||||
*/
|
||||
|
||||
/**
|
||||
* get esptouchResult length of one
|
||||
* @return length of one
|
||||
*/
|
||||
- (int) getEsptouchResultOneLen;
|
||||
|
||||
/**
|
||||
* get esptouchResult length of mac
|
||||
* @return length of mac
|
||||
*/
|
||||
- (int) getEsptouchResultMacLen;
|
||||
|
||||
/**
|
||||
* get esptouchResult length of ip
|
||||
* @return length of ip
|
||||
*/
|
||||
- (int) getEsptouchResultIpLen;
|
||||
|
||||
/**
|
||||
* get esptouchResult total length
|
||||
* @return total length
|
||||
*/
|
||||
- (int) getEsptouchResultTotalLen;
|
||||
|
||||
/**
|
||||
* get port for listening(used by server)
|
||||
* @return port for listening(used by server)
|
||||
*/
|
||||
- (int) getPortListening;
|
||||
|
||||
/**
|
||||
* get target hostname
|
||||
* @return target hostame(used by client)
|
||||
*/
|
||||
- (NSString *) getTargetHostname;
|
||||
|
||||
/**
|
||||
* get target port
|
||||
* @return target port(used by client)
|
||||
*/
|
||||
- (int) getTargetPort;
|
||||
|
||||
/**
|
||||
* get millisecond for waiting udp receiving(receiving without sending)
|
||||
* @return millisecond for waiting udp receiving(receiving without sending)
|
||||
*/
|
||||
- (int) getWaitUdpReceivingMillisecond;
|
||||
|
||||
/**
|
||||
* get millisecond for waiting udp sending(sending including receiving)
|
||||
* @return millisecond for waiting udep sending(sending including receiving)
|
||||
*/
|
||||
- (int) getWaitUdpSendingMillisecond;
|
||||
|
||||
/**
|
||||
* get millisecond for waiting udp sending and receiving
|
||||
* @return millisecond for waiting udp sending and receiving
|
||||
*/
|
||||
- (int) getWaitUdpTotalMillisecond;
|
||||
|
||||
/**
|
||||
* get the threshold for how many correct broadcast should be received
|
||||
* @return the threshold for how many correct broadcast should be received
|
||||
*/
|
||||
- (int) getThresholdSucBroadcastCount;
|
||||
|
||||
/**
|
||||
* set the millisecond for waiting udp sending and receiving
|
||||
* @param waitUdpTotalMillisecond the millisecond for waiting udp sending and receiving
|
||||
*/
|
||||
- (void) setWaitUdpTotalMillisecond: (int) waitUdpTotalMillisecond;
|
||||
|
||||
|
||||
/**
|
||||
* get the count of expect task results
|
||||
* @return the count of expect task results
|
||||
*/
|
||||
- (int) getExpectTaskResultCount;
|
||||
|
||||
/**
|
||||
* set the count of expect task results
|
||||
* @param expectTaskResultCount the count of expect task results
|
||||
*/
|
||||
- (void) setExpectTaskResultCount: (int) expectTaskResultCount;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,174 @@
|
||||
//
|
||||
// ESPTaskParameter.m
|
||||
// EspTouchDemo
|
||||
//
|
||||
// Created by 白 桦 on 5/20/15.
|
||||
// Copyright (c) 2015 白 桦. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ESPTouchTaskParameter.h"
|
||||
|
||||
@interface ESPTaskParameter()
|
||||
@property (nonatomic,assign) long intervalGuideCodeMillisecond;
|
||||
@property (nonatomic,assign) long intervalDataCodeMillisecond;
|
||||
@property (nonatomic,assign) long timeoutGuideCodeMillisecond;
|
||||
@property (nonatomic,assign) long timeoutDataCodeMillisecond;
|
||||
@property (nonatomic,assign) long timeoutTotalCodeMillisecond;
|
||||
@property (nonatomic,assign) int totalRepeatTime;
|
||||
@property (nonatomic,assign) int esptouchResultOneLen;
|
||||
@property (nonatomic,assign) int esptouchResultMacLen;
|
||||
@property (nonatomic,assign) int esptouchResultIpLen;
|
||||
@property (nonatomic,assign) int esptouchResultTotalLen;
|
||||
@property (nonatomic,assign) int portListening;
|
||||
@property (nonatomic,assign) int targetPort;
|
||||
@property (nonatomic,assign) int waitUdpReceivingMillisecond;
|
||||
@property (nonatomic,assign) int waitUdpSendingMillisecond;
|
||||
@property (nonatomic,assign) int thresholdSucBroadcastCount;
|
||||
@property (nonatomic,assign) int expectTaskResultCount;
|
||||
@end
|
||||
|
||||
@implementation ESPTaskParameter
|
||||
|
||||
static int _datagramCount = 0;
|
||||
|
||||
- (id) init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.intervalGuideCodeMillisecond = 10;
|
||||
self.intervalDataCodeMillisecond = 10;
|
||||
self.timeoutGuideCodeMillisecond = 2000;
|
||||
self.timeoutDataCodeMillisecond = 4000;
|
||||
self.timeoutTotalCodeMillisecond = 2000 + 4000;
|
||||
self.totalRepeatTime = 1;
|
||||
self.esptouchResultOneLen = 1;
|
||||
self.esptouchResultMacLen = 6;
|
||||
self.esptouchResultIpLen = 4;
|
||||
self.esptouchResultTotalLen = 1 + 6 + 4;
|
||||
self.portListening = 18266;
|
||||
self.targetPort = 7001;
|
||||
self.waitUdpReceivingMillisecond = 15000;
|
||||
self.waitUdpSendingMillisecond = 45000;
|
||||
self.thresholdSucBroadcastCount = 1;
|
||||
self.expectTaskResultCount = 1;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
// the range of the result should be 1-100
|
||||
- (int) __getNextDatagramCount
|
||||
{
|
||||
return 1 + (_datagramCount++) % 100;
|
||||
}
|
||||
|
||||
- (long) getIntervalGuideCodeMillisecond
|
||||
{
|
||||
return self.intervalGuideCodeMillisecond;
|
||||
}
|
||||
|
||||
- (long) getIntervalDataCodeMillisecond
|
||||
{
|
||||
return self.intervalDataCodeMillisecond;
|
||||
}
|
||||
|
||||
- (long) getTimeoutGuideCodeMillisecond
|
||||
{
|
||||
return self.timeoutGuideCodeMillisecond;
|
||||
}
|
||||
|
||||
- (long) getTimeoutDataCodeMillisecond
|
||||
{
|
||||
return self.timeoutDataCodeMillisecond;
|
||||
}
|
||||
|
||||
- (long) getTimeoutTotalCodeMillisecond
|
||||
{
|
||||
return self.timeoutTotalCodeMillisecond;
|
||||
}
|
||||
|
||||
- (int) getTotalRepeatTime
|
||||
{
|
||||
return self.totalRepeatTime;
|
||||
}
|
||||
|
||||
- (int) getEsptouchResultOneLen
|
||||
{
|
||||
return self.esptouchResultOneLen;
|
||||
}
|
||||
|
||||
|
||||
- (int) getEsptouchResultMacLen
|
||||
{
|
||||
return self.esptouchResultMacLen;
|
||||
}
|
||||
|
||||
|
||||
- (int) getEsptouchResultIpLen
|
||||
{
|
||||
return self.esptouchResultIpLen;
|
||||
}
|
||||
|
||||
|
||||
- (int) getEsptouchResultTotalLen
|
||||
{
|
||||
return self.esptouchResultTotalLen;
|
||||
}
|
||||
|
||||
- (int) getPortListening
|
||||
{
|
||||
return self.portListening;
|
||||
}
|
||||
|
||||
// target hostname is : 234.1.1.1, 234.2.2.2, 234.3.3.3 to 234.100.100.100
|
||||
- (NSString *) getTargetHostname
|
||||
{
|
||||
int count = [self __getNextDatagramCount];
|
||||
return [NSString stringWithFormat: @"234.%d.%d.%d", count, count, count];
|
||||
}
|
||||
|
||||
- (int) getTargetPort
|
||||
{
|
||||
return self.targetPort;
|
||||
}
|
||||
|
||||
- (int) getWaitUdpReceivingMillisecond
|
||||
{
|
||||
return self.waitUdpReceivingMillisecond;
|
||||
}
|
||||
|
||||
- (int) getWaitUdpSendingMillisecond
|
||||
{
|
||||
return self.waitUdpSendingMillisecond;
|
||||
}
|
||||
|
||||
- (int) getWaitUdpTotalMillisecond
|
||||
{
|
||||
return self.waitUdpReceivingMillisecond + self.waitUdpSendingMillisecond;
|
||||
}
|
||||
|
||||
- (int) getThresholdSucBroadcastCount
|
||||
{
|
||||
return self.thresholdSucBroadcastCount;
|
||||
}
|
||||
|
||||
- (void) setWaitUdpTotalMillisecond: (int) waitUdpTotalMillisecond
|
||||
{
|
||||
if (waitUdpTotalMillisecond < self.waitUdpReceivingMillisecond + [self getTimeoutTotalCodeMillisecond])
|
||||
{
|
||||
// if it happen, even one turn about sending udp broadcast can't be completed
|
||||
NSLog(@"ESPTouchTaskParameter waitUdpTotalMillisecod is invalid, it is less than mWaitUdpReceivingMilliseond + [self getTimeoutTotalCodeMillisecond]");
|
||||
assert(0);
|
||||
}
|
||||
self.waitUdpSendingMillisecond = waitUdpTotalMillisecond - self.waitUdpReceivingMillisecond;
|
||||
}
|
||||
|
||||
- (int) getExpectTaskResultCount
|
||||
{
|
||||
return self.expectTaskResultCount;
|
||||
}
|
||||
|
||||
- (void) setExpectTaskResultCount: (int) expectTaskResultCount
|
||||
{
|
||||
_expectTaskResultCount = expectTaskResultCount;
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// ESPUDPSocketClient.h
|
||||
// EspTouchDemo
|
||||
//
|
||||
// Created by 白 桦 on 4/13/15.
|
||||
// Copyright (c) 2015 白 桦. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface ESPUDPSocketClient : NSObject
|
||||
|
||||
- (void) close;
|
||||
|
||||
- (void) interrupt;
|
||||
|
||||
/**
|
||||
* send the data by UDP
|
||||
*
|
||||
* @param bytes
|
||||
* the array of datas to be sent
|
||||
* @param targetHost
|
||||
* the host name of target, e.g. 192.168.1.101
|
||||
* @param targetPort
|
||||
* the port of target
|
||||
* @param interval
|
||||
* the milliseconds to between each UDP sent
|
||||
*/
|
||||
- (void) sendDataWithBytesArray2: (NSArray *) bytesArray2 ToTargetHostName: (NSString *)targetHostName WithPort: (int) port
|
||||
andInterval: (long) interval;
|
||||
|
||||
/**
|
||||
* send the data by UDP
|
||||
*
|
||||
* @param data
|
||||
* the data to be sent
|
||||
* @param offset
|
||||
* the offset which data to be sent
|
||||
* @param count
|
||||
* the count of the data
|
||||
* @param targetHost
|
||||
* the host name of target, e.g. 192.168.1.101
|
||||
* @param targetPort
|
||||
* the port of target
|
||||
* @param interval
|
||||
* the milliseconds to between each UDP sent
|
||||
*/
|
||||
- (void) sendDataWithBytesArray2: (NSArray *) bytesArray2 Offset: (NSUInteger) offset Count: (NSUInteger) count ToTargetHostName: (NSString *)targetHostName WithPort: (int) port
|
||||
andInterval: (long) interval;
|
||||
@end
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
//
|
||||
// ESPUDPSocketClient.m
|
||||
// EspTouchDemo
|
||||
//
|
||||
// Created by 白 桦 on 4/13/15.
|
||||
// Copyright (c) 2015 白 桦. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ESPUDPSocketClient.h"
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "ESPTouchTask.h"
|
||||
|
||||
@interface ESPUDPSocketClient ()
|
||||
|
||||
@property(nonatomic, assign) int _sck_fd;
|
||||
@property(nonatomic, assign) BOOL _isStop;
|
||||
// it is used to check whether the socket is closed already to prevent close more than once.
|
||||
// especially, when you close the socket second time, it is created just now, it will crash.
|
||||
//
|
||||
// // suppose fd1 = 4, fd1 belong to obj1
|
||||
// e.g. int fd1 = socket(AF_INET,SOCK_DRAM,0);
|
||||
// close(fd1);
|
||||
//
|
||||
// // suppose fd2 = 4 as well, fd2 belong to obj2
|
||||
// int fd2 = socket(AF_INET,SOCK_DRAM,0);
|
||||
//
|
||||
// // obj1's dealloc() is called by system, so
|
||||
// close(fd1);
|
||||
//
|
||||
// // Amazing!!! at the moment, fd2 is close by others
|
||||
//
|
||||
@property(nonatomic,assign) volatile BOOL _isClosed;
|
||||
// it is used to lock the close method
|
||||
@property(nonatomic,strong) volatile NSLock *_lock;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ESPUDPSocketClient
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
self._isStop = NO;
|
||||
self._sck_fd = socket(AF_INET,SOCK_DGRAM,0);
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"##########################client init() _sck_fd=%d",self._sck_fd);
|
||||
}
|
||||
if (self._sck_fd < 0)
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
perror("client: init() _skd_fd init fail\n");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
// make sure the socket will be closed sometime
|
||||
- (void)dealloc
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"###################client dealloc()");
|
||||
}
|
||||
[self close];
|
||||
}
|
||||
|
||||
- (void) close
|
||||
{
|
||||
[self._lock lock];
|
||||
if (!self._isClosed)
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"###################client close() fd=%d",self._sck_fd);
|
||||
}
|
||||
close(self._sck_fd);
|
||||
self._isClosed = YES;
|
||||
}
|
||||
[self._lock unlock];
|
||||
}
|
||||
|
||||
- (void) interrupt
|
||||
{
|
||||
self._isStop = YES;
|
||||
}
|
||||
|
||||
- (void) sendDataWithBytesArray2: (NSArray *) bytesArray2 ToTargetHostName: (NSString *)targetHostName WithPort: (int) port
|
||||
andInterval: (long) interval
|
||||
{
|
||||
return [self sendDataWithBytesArray2:bytesArray2 Offset:0 Count:[bytesArray2 count] ToTargetHostName:targetHostName WithPort:port andInterval:interval];
|
||||
}
|
||||
|
||||
- (void) sendDataWithBytesArray2: (NSArray *) bytesArray2 Offset: (NSUInteger) offset Count: (NSUInteger) count ToTargetHostName: (NSString *)targetHostName WithPort: (int) port
|
||||
andInterval: (long) interval
|
||||
{
|
||||
// check data is valid
|
||||
if (nil == bytesArray2 || 0 == [bytesArray2 count])
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
perror("client: data is null or data's length equals 0, so sendData fail\n");
|
||||
}
|
||||
[self close];
|
||||
return;
|
||||
}
|
||||
// init socket parameters
|
||||
bool isBroadcast = [targetHostName isEqualToString:@"255.255.255.255"];
|
||||
socklen_t addr_len;
|
||||
struct sockaddr_in target_addr;
|
||||
memset(&target_addr, 0, sizeof(target_addr));
|
||||
target_addr.sin_family = AF_INET;
|
||||
target_addr.sin_addr.s_addr = inet_addr([targetHostName cStringUsingEncoding:NSASCIIStringEncoding]);
|
||||
target_addr.sin_port = htons(port);
|
||||
addr_len = sizeof(target_addr);
|
||||
if (isBroadcast) {
|
||||
const int opt = 1;
|
||||
// set whether the socket is broadcast or not
|
||||
if (setsockopt(self._sck_fd,SOL_SOCKET,SO_BROADCAST,(char *)&opt, sizeof(opt)) < 0)
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
perror("client: setsockopt SO_BROADCAST fail, but just ignore it\n");
|
||||
}
|
||||
// for the Ap will make some troubles when the phone send too many UDP packets,
|
||||
// but we don't expect the UDP packet received by others, so just ignore it
|
||||
}
|
||||
}
|
||||
// send data gotten from the array
|
||||
for (NSUInteger i = offset; !self._isStop && i < offset + count; i++) {
|
||||
// get data
|
||||
NSData* data = [bytesArray2 objectAtIndex:i];
|
||||
NSUInteger dataLen = [data length];
|
||||
if (0 == dataLen)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Byte bytes[dataLen];
|
||||
[data getBytes:bytes length:dataLen];
|
||||
// send data
|
||||
if (sendto(self._sck_fd, bytes, dataLen, 0, (struct sockaddr*)&target_addr, addr_len) < 0)
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
perror("client: sendto fail, but just ignore it\n");
|
||||
}
|
||||
// for the Ap will make some troubles when the phone send too many UDP packets,
|
||||
// but we don't expect the UDP packet received by others, so just ignore it
|
||||
}
|
||||
// sleep interval
|
||||
usleep((useconds_t)(interval*1000));
|
||||
}
|
||||
// check whether the client is stop
|
||||
if (self._isStop) {
|
||||
[self close];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// ESPUDPSocketServer.h
|
||||
// EspTouchDemo
|
||||
//
|
||||
// Created by 白 桦 on 4/13/15.
|
||||
// Copyright (c) 2015 白 桦. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#define BUFFER_SIZE 64
|
||||
|
||||
@interface ESPUDPSocketServer : NSObject
|
||||
{
|
||||
@private
|
||||
Byte _buffer[BUFFER_SIZE];
|
||||
}
|
||||
|
||||
- (void) close;
|
||||
|
||||
- (void) interrupt;
|
||||
|
||||
/**
|
||||
* Set the socket timeout in milliseconds
|
||||
*
|
||||
* @param timeout
|
||||
* the timeout in milliseconds or 0 for no timeout.
|
||||
* @return true whether the timeout is set suc
|
||||
*/
|
||||
- (void) setSocketTimeout: (int) timeout;
|
||||
|
||||
/**
|
||||
* Receive one byte from the port
|
||||
*
|
||||
* @return one byte receive from the port or UINT8_MAX(it impossible receive it from the socket)
|
||||
*/
|
||||
- (Byte) receiveOneByte;
|
||||
|
||||
- (NSData *) receiveSpecLenBytes: (int)len;
|
||||
|
||||
- (id) initWithPort: (int) port AndSocketTimeout: (int) socketTimeout;
|
||||
|
||||
@end
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
//
|
||||
// ESPUDPSocketServer.m
|
||||
// EspTouchDemo
|
||||
//
|
||||
// Created by 白 桦 on 4/13/15.
|
||||
// Copyright (c) 2015 白 桦. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ESPUDPSocketServer.h"
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/types.h>
|
||||
#include "ESPTouchTask.h"
|
||||
|
||||
@interface ESPUDPSocketServer ()
|
||||
|
||||
@property(nonatomic,assign) int _sck_fd;
|
||||
@property(nonatomic,assign) int _port;
|
||||
// it is used to check whether the socket is closed already to prevent close more than once.
|
||||
// especially, when you close the socket second time, it is created just now, it will crash.
|
||||
//
|
||||
// // suppose fd1 = 4, fd1 belong to obj1
|
||||
// e.g. int fd1 = socket(AF_INET,SOCK_DRAM,0);
|
||||
// close(fd1);
|
||||
//
|
||||
// // suppose fd2 = 4 as well, fd2 belong to obj2
|
||||
// int fd2 = socket(AF_INET,SOCK_DRAM,0);
|
||||
//
|
||||
// // obj1's dealloc() is called by system, so
|
||||
// close(fd1);
|
||||
//
|
||||
// // Amazing!!! at the moment, fd2 is close by others
|
||||
//
|
||||
@property(nonatomic,assign) volatile bool _isClosed;
|
||||
// it is used to lock the close method
|
||||
@property(nonatomic,strong) volatile NSLock *_lock;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ESPUDPSocketServer
|
||||
|
||||
- (id) initWithPort: (int) port AndSocketTimeout: (int) socketTimeout
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
// create local
|
||||
self._lock = [[NSLock alloc]init];
|
||||
// create socket
|
||||
self._isClosed = NO;
|
||||
self._sck_fd = socket(AF_INET,SOCK_DGRAM,0);
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"##########################server init(): _sck_fd=%d", self._sck_fd);
|
||||
}
|
||||
if (self._sck_fd < 0)
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
perror("server: _skd_fd init() fail\n");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
// init socket params
|
||||
struct sockaddr_in server_addr;
|
||||
socklen_t addr_len;
|
||||
memset(&server_addr, 0, sizeof(server_addr));
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_port = htons(port);
|
||||
server_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
addr_len = sizeof(server_addr);
|
||||
// set broadcast
|
||||
const int opt = 1;
|
||||
if (setsockopt(self._sck_fd,SOL_SOCKET,SO_BROADCAST,(char *)&opt, sizeof(opt)) < 0)
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
perror("server init(): setsockopt SO_BROADCAST fail\n");
|
||||
}
|
||||
[self close];
|
||||
return nil;
|
||||
}
|
||||
// set timeout
|
||||
[self setSocketTimeout:socketTimeout];
|
||||
// bind
|
||||
if (bind(self._sck_fd, (struct sockaddr*)&server_addr, addr_len) < 0)
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
perror("server init(): bind fail\n");
|
||||
}
|
||||
[self close];
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
// make sure the socket will be closed sometime
|
||||
- (void)dealloc
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"###################server dealloc()");
|
||||
}
|
||||
[self close];
|
||||
}
|
||||
|
||||
- (void) close
|
||||
{
|
||||
[self._lock lock];
|
||||
if (!self._isClosed)
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
NSLog(@"###################server close() fd=%d",self._sck_fd);
|
||||
}
|
||||
close(self._sck_fd);
|
||||
self._isClosed = true;
|
||||
}
|
||||
[self._lock unlock];
|
||||
}
|
||||
|
||||
- (void) interrupt
|
||||
{
|
||||
[self close];
|
||||
}
|
||||
|
||||
- (void) setSocketTimeout: (int) timeout
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = timeout/1000;
|
||||
tv.tv_usec = timeout%1000*1000;
|
||||
if (setsockopt(self._sck_fd,SOL_SOCKET,SO_RCVTIMEO,(char *)&tv, sizeof(tv)) < 0)
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
perror("server: setsockopt SO_RCVTIMEO fail\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (Byte) receiveOneByte
|
||||
{
|
||||
ssize_t recNumber = recv(self._sck_fd, _buffer, BUFFER_SIZE, 0);
|
||||
if (recNumber > 0)
|
||||
{
|
||||
return _buffer[0];
|
||||
}
|
||||
else if(recNumber == 0)
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
perror("server: receiveOneByte socket is closed by the other\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
perror("server: receiveOneByte fail\n");
|
||||
}
|
||||
}
|
||||
return UINT8_MAX;
|
||||
}
|
||||
|
||||
- (NSData *) receiveSpecLenBytes: (int)len
|
||||
{
|
||||
ssize_t recNumber = recv(self._sck_fd, _buffer, BUFFER_SIZE, 0);
|
||||
if (recNumber==len)
|
||||
{
|
||||
NSData *data = [[NSData alloc]initWithBytes:_buffer length:recNumber];
|
||||
return data;
|
||||
}
|
||||
else if(recNumber==0)
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
perror("server: receiveOneByte socket is closed by the other\n");
|
||||
}
|
||||
}
|
||||
else if(recNumber<0)
|
||||
{
|
||||
if (DEBUG_ON)
|
||||
{
|
||||
perror("server: receiveOneByte fail\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// receive rubbish message, just ignore it
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user