Skip to content

Instantly share code, notes, and snippets.

@tgherzog
Last active November 19, 2015 05:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tgherzog/7ac2baee8f782e7e5e2e to your computer and use it in GitHub Desktop.
Save tgherzog/7ac2baee8f782e7e5e2e to your computer and use it in GitHub Desktop.
Stuff for the Sail Buddy App

NMEA Documentation

NMEA 0183 Specification

Fragmented evidence on depth sounder sentences:

Scroll Views

C Interface

http://stackoverflow.com/questions/24146488/swift-pass-uninitialized-c-structure-to-imported-c-function

Customized Table Sections

http://www.ioscreator.com/tutorials/customizing-header-footer-table-view-ios8-swift

Today Widget

Using Optionals

Variable declarations

var foo:Int? // declare an optional value: use foo! to unwrap
var foo:Int! // implicitly unwrapped optional: foo! is not required

Class member access

var foo = bar?.bat // optional chaining: foo is nil if bar is nil
var foo = bar!.bat // runtime error if bar is nil

Casting

var foo as ClassName  // ordinary casting will fail for down casting
var foo as? ClassName // downcast to optional: return nil on failure
var foo as! ClassName // forced downcast: runtime error on failure

Function returns

func doSomething() -> Int { }    // ordinary return
func doSomething() -> Int? { }   // return optional
func doSomething() -> Int! { }   // return implicitly unwrapped value: not sure how this is useful

Exception Handling

var foo = try  funcThatThrows() // call a throwing function in the context of a do { }
var foo = try? funcThatThrows() // foo is nil if function throws an exception
var foo = try! funcThatThrows() // disable exception throwing when you know function will succeed
<?php
/* Sets up a TCP or UDP broadcast process point that emulates the base unit of a sail timer wind vane
Supported arguments:
--port=port_number (default: 55554)
--input=data_file (default: sailtimer.txt)
--mode=1 - transmits data in randomly-sized blocks instead of complete nmea sentences (default: 0)
--type=tcp|udp - set socket type (default: udp)
Some resources:
http://www.ccplusplus.com/2011/09/udp-broadcast-client-server-example.html
http://www.tack.ch/multicast/broadcast.shtml
http://stackoverflow.com/questions/11135801/how-to-broadcast-message-using-udp-sockets-locally
https://www.google.com/#q=udp+broadcast+example+code
*/
$ip_address = getHostByName(getHostName());
$port = 55554;
$input_file = 'sailtimer.txt';
$mode = 0;
$ntype = 'udp';
$args = $argv;
array_shift($args);
while( substr($args[0],0,2) === '--' ) {
list($key,$value) = explode('=', substr($args[0],2), 2);
switch($key) {
case 'port':
$port = $value;
break;
case 'input':
$input_file = $value;
break;
case 'type':
$ntype = $value;
break;
case 'mode':
$mode = $value;
break;
}
array_shift($args);
}
if( $ntype == 'tcp' ) {
print "Initiating $ntype connection at $ip_address on port $port\n";
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if( $socket === false ) { die("socket_create failed.\n"); }
if( socket_bind($socket, $ip_address, $port) === false ) {
die("socket_bind() failed: " . socket_strerror(socket_last_error($socket)) . "\n");
}
if( socket_listen($socket, 5) === false ) {
die("socket_listen() failed: " . socket_strerror(socket_last_error($socket)) . "\n");
}
if( ($socketConnection = socket_accept($socket)) === false ) {
die("socket_accept() failed: " . socket_strerror(socket_last_error($socket)) . "\n");
}
socket_getpeername($socketConnection, $peerAddress);
print "Connection accepted: $peerAddress\n";
}
elseif( $ntype == 'udp' ) {
print "Initiating $ntype connection on port $port\n";
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
if( $socket === false ) { die("socket_create failed.\n"); }
//Set socket options.
socket_set_nonblock($socket);
socket_set_option($socket, SOL_SOCKET, SO_BROADCAST, 1);
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
if (defined('SO_REUSEPORT'))
socket_set_option($socket, SOL_SOCKET, SO_REUSEPORT, 1);
}
else {
die("Unknown connection type: $ntype\n");
}
//Bind to any address & port
/*
if(!socket_bind($socket, '127.0.0.1', 0))
die("socket_bind failed.\n");
*/
$contents = file_get_contents($input_file);
$len = strlen($contents);
$m = 0;
// ping every 2 seconds
while( true ) {
$msg = '';
if( $mode == 0 ) {
while( true ) {
$i = substr($contents, $m, 1);
$m++;
$msg .= $i;
if( $m == $len ) {
$m = 0;
break;
}
elseif( ord($i) == 0x0a ) break;
}
}
else {
$i = rand(1,32) + 8;
$i = min($len - $m, $i);
$msg = substr($contents, $m, $i);
$m += $i;
if( $len == $m ) $m = 0;
}
if( $ntype == 'tcp' ) {
if( @socket_recv($socketConnection, $tmpBuffer, 1, MSG_PEEK|MSG_DONTWAIT) === false ) {
$errorcode = socket_last_error($socketConnection);
if( $errorcode != 35 ) {
print "closing. error is $errorcode / " . socket_strerror($errorcode) . "\n";
socket_close($socketConnection);
break;
}
}
socket_write($socketConnection, $msg, strlen($msg));
}
elseif( $ntype == 'udp' ) {
socket_sendto($socket, $msg, strlen($msg), 0, '255.255.255.255', $port);
}
# print $msg;
# sleep randomly, 0.5-2.0 seconds
usleep((500 + rand(0,1500)) * 1000);
}
socket_close($socket);
/*
//Wait for data.
$read = array($socket); $write = NULL; $except = NULL;
while(socket_select($read, $write, $except, NULL)) {
//Read received packets with a maximum size of 5120 bytes.
while(is_string($data = socket_read($socket, 5120))) {
echo $data;
}
}
*/
$WIMWV,040.0,R,14.2,K,A*15
$SDDBT,53.4,f,16.3,M,8.9,F*37
$SDDPT,16.3,0.4*67
$WIMWV,049.0,R,09.7,K,A*15
$WIMWV,061.0,R,13.1,K,A*12
$WIBAT,1,7*4F
$SDDBT,55.4,f,16.9,M,9.2,F*35
$SDDPT,16.9,0.4*73
$WIMWV,061.0,R,14.1,K,A*15
$WIMWV,045.0,R,13.1,K,A*14
$SDDBT,54.2,f,16.5,M,9.0,F*42
$SDDPT,16.5,0.4*69
$WIMWV,064.0,R,12.9,K,A*1E
$WIMWV,055.0,R,12.7,K,A*12
$SDDBT,53.7,f,16.4,M,9.0,F*41
$SDDPT,16.4,0.4*68
$WIMWV,049.0,R,11.8,K,A*13
$WIMWV,049.0,R,10.5,K,A*1F
$SDDBT,53.5,f,16.3,M,8.9,F*36
$SDDPT,16.3,0.4*67
$WIMWV,032.0,R,09.0,K,A*1E
$WIMWV,029.0,R,09.3,K,A*17
$SDDBT,52.6,f,16.0,M,8.8,F*36
$SDDPT,16.0,0.4*64
$WIMWV,011.0,R,05.7,K,A*14
$SDDBT,50.0,f,15.2,M,8.3,F*42
$SDDPT,15.2,0.4*65
$WIMWV,030.0,R,06.1,K,A*12
$WIBAT,1,7*4F
$SDDBT,61.0,f,18.6,M,10.2,F*25
$SDDPT,18.6,0.4*72
$WIMWV,026.0,R,09.0,K,A*1B
$SDDBT,61.5,f,18.8,M,10.3,F*19
$SDDPT,18.8,0.4*70
$WIMWV,019.0,R,10.3,K,A*1C
$SDDBT,49.6,f,15.1,M,8.3,F*39
$SDDPT,15.1,0.4*66
$WIMWV,027.0,R,12.0,K,A*10
$SDDBT,52.9,f,16.1,M,8.8,F*42
$SDDPT,16.1,0.4*65
$WIMWV,030.0,R,13.9,K,A*1E
$SDDBT,55.1,f,16.8,M,9.2,F*39
$SDDPT,16.8,0.4*72
$WIMWV,029.0,R,12.1,K,A*1F
$SDDBT,58.2,f,17.7,M,9.7,F*34
$SDDPT,17.7,0.4*70
$WIMWV,013.0,R,16.6,K,A*15
$SDDBT,57.5,f,17.5,M,9.6,F*41
$SDDPT,17.5,0.4*68
$WIMWV,013.0,R,14.0,K,A*11
$SDDBT,54.3,f,16.6,M,9.0,F*40
$SDDPT,16.6,0.4*70
$WIMWV,040.0,R,16.6,K,A*13
$WIMWV,015.0,R,12.9,K,A*18
$WIBAT,1,7*4F
$SDDBT,51.4,f,15.7,M,8.6,F*47
$SDDPT,15.7,0.4*68
$WIMWV,042.0,R,13.3,K,A*11
$WIMWV,035.0,R,13.5,K,A*17
$WIMWV,033.0,R,08.9,K,A*17
$SDDBT,55.2,f,16.8,M,9.2,F*36
$SDDPT,16.8,0.4*72
$WIMWV,031.0,R,08.7,K,A*1B
$WIMWV,031.0,R,08.5,K,A*19
$SDDBT,61.4,f,18.7,M,10.2,F*28
$SDDPT,18.7,0.4*73
$WIMWV,039.0,R,11.3,K,A*1F
$WIMWV,015.0,R,12.4,K,A*15
$SDDBT,55.5,f,16.9,M,9.3,F*35
$SDDPT,16.9,0.4*73
$WIMWV,020.0,R,11.0,K,A*14
$WIMWV,016.0,R,09.0,K,A*18
$SDDBT,61.2,f,18.6,M,10.2,F*27
$SDDPT,18.6,0.4*72
$WIMWV,024.0,R,10.1,K,A*10
$WIBAT,1,7*4F
$WIMWV,022.0,R,09.1,K,A*1E
$SDDBT,55.0,f,16.8,M,9.2,F*38
$SDDPT,16.8,0.4*72
$WIMWV,018.0,R,13.5,K,A*18
$WIMWV,010.0,R,10.2,K,A*14
$SDDBT,53.1,f,16.2,M,8.9,F*33
$SDDPT,16.2,0.4*66
$WIMWV,027.0,R,11.5,K,A*16
$WIMWV,023.0,R,10.6,K,A*10
$SDDBT,53.3,f,16.2,M,8.9,F*35
$SDDPT,16.2,0.4*66
$WIMWV,026.0,R,13.2,K,A*12
$WIMWV,024.0,R,12.4,K,A*17
$SDDBT,56.8,f,17.3,M,9.5,F*32
$SDDPT,17.3,0.4*66
$WIMWV,024.0,R,13.9,K,A*1B
$WIMWV,016.0,R,12.6,K,A*14
$SDDBT,51.0,f,15.6,M,8.5,F*41
$SDDPT,15.6,0.4*69
$WIMWV,027.0,R,12.4,K,A*14
<?php
function tws($awa,$aws,$cog,$sog) {
$speed = $aws * $aws + $sog * $sog - 2.0 * $aws * $sog * cos( deg2rad($awa*$cog) );
return sqrt( $speed );
}
function twa($awa, $aws, $cog, $sog) {
$speed = tws($awa, $aws, $cog, $sog);
if( $speed == 0 ) {
return 0; // we're not moving
}
$angle = acos( ($aws * cos( deg2rad($awa)) - $sog) / $speed);
if( $awa > 180 ) $angle *= -1;
return rad2deg( $angle );
}
$args = $argv;
array_shift($args);
list($awa, $aws, $cog, $sog) = $args;
$angle = twa($awa, $aws, $cog, $sog);
$speed = tws($awa, $aws, $cog, $sog);
print <<<HERE
AWA: $awa
AWS: $aws
TWA: $angle
TWS: $speed
COG: $cog
SOG: $sog
HERE;
// Using these calculations: https://en.wikipedia.org/wiki/Apparent_wind
var trueWindSpeed:CLLocationSpeed? {
if let course = self.course, aws = apparentWindSpeed, awa = apparentWindAngle, sog = self.speed {
var speed:Double = aws*aws + sog*sog - 2.0*aws*sog * cos(deg2rad(degnormalize(awa+course)))
return sqrt(speed)
}
return nil
}
var trueWindAngle:CLLocationDirection? {
if let aws = apparentWindSpeed, awa = apparentWindAngle, sog = self.speed, tws = trueWindSpeed {
// trap for div by 0
if tws == 0.0 {
return 0
}
var angle:Double = acos( (aws*cos(deg2rad(awa)) - sog) / tws)
if awa > 180 {
angle *= -1
}
return rad2deg(angle)
}
return nil
}
func deg2rad(degrees: CLLocationDirection) -> Double {
return degrees * 3.14159 / 180.0
}
func rad2deg(rad: Double) -> CLLocationDirection {
return round(rad * 180.0 / 3.14159)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment