APRS-IS paikkatietosovellus (1) lähettää käyttäjän sijainnin datayhteyden kautta APRS-IS palvelimelle (2).
Ohjelman käyttöliittymä perustuu Pivot käyttöliittymämalliin.
Sovellus koostuu neljästä sivusta (MainPage.xaml). Pääsivulla (Location, GPS) näytetään sijainti, nopeus, suunta, korkeus & paikannuksen tarkkuus), painike jolla aloitetaan/lopetetaan tietojen näyttäminen ja lähettäminen APRS-IS palvelimelle. Näytön yläosassa näytetään APRS-IS tietopaketin tiedot.
Configuration sivulla annetaan asetustiedot: radioamatöörikutsu, server passcode (3), palvelimen IP-osoite ja porttinumero, nimi & info teksti ja pollaus tiheys (1-60 minuuttia), jolla asetetaan se, kuinka usein paketti lähetetään APRS-IS palvelimelle. Tiedot talletetaan isolated storage alueelle.(IsoStoHandler.cs)
APRS tietopaketti lähetetään TCP:llä (* TCP NO_DELAY *) määriteltyyn APRS-IS palvelimelle. Paketin rakenne on:
1>APRS,TCPIP*:!latitude/longitude23/45
1 = radioamatöörikutsu
2 = APRS symboli
3 = kompassisuunta
4 = nopeus, maileina/tunti, (dSpeed * 3.6) / 1.852 = muunnos mp/h => km/h)
5 = nimi/info
1. http://www.aprs.fi
2. http://wiki.ham.fi/APRS-IS (teknistä tietoa kehittäjille: http://www.aprs-is.net)
3. http://aprs.ham.fi/laskuri
-------------------------------------------------------------------------------------------------------------------------------------------------
MainPage.xaml.cs
// APRS-IS client for Windows Phone by OH1GIU
// Developed and tested (in WP emulator) with Windows Phone 7.1 (Mango) SDK
// THIS SOURCE CODE IS FREE
// You can freely use this source code in your own projects and applications released in the Windows Phone marketplace.
//
// When building/deploying for real device change gensets.TEST_MODE value to false (gensets.cs)
// Tnx to OH1KO & OH7LZB for help and advices !!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Info;
using System.Device.Location;
using System.Net.Sockets;
using System.Windows.Threading;
using System.Threading;
namespace wpAPRS
{
public partial class MainPage : PhoneApplicationPage
{
private GeoCoordinateWatcher watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
private double dLat = 0;
private double dLon = 0;
private double dCourse = Double.NaN;
private double dSpeed = Double.NaN;
private int iTcpPort;
private bool bConnection = false;
private bool bPos = false;
Socket socketAPRS = null;
static ManualResetEvent done = new ManualResetEvent(false);
private string aprsMsg = string.Empty;
private DispatcherTimer timer = new DispatcherTimer();
private System.Text.StringBuilder sb = new System.Text.StringBuilder();
private string sendData = string.Empty;
private bool bSlider = false;
private bool bIsAprsOn = false;
private IsoStoHandler isoSto;
private bool bStart = true;
private string[] sAprs_data = new string[8] {"","","","","","","",""};
private string aprsSym = ">"; // APRS symboli http://wiki.ham.fi/APRS_symboli
private gpsutil gutil = null;
private string strLogin = string.Empty;
private bool bShowLoginStr = true;
private bool bSocketError = false;
// Constructor
public MainPage()
{
InitializeComponent();
DataContext = App.ViewModel;
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
ClearLocTexts();
GetAboutInfo();
bSlider = true;
textBlockLocSpc.Text = gensets.APRS_SERVER_NO_CONN;
watcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);
this.timer.Tick += new EventHandler(timer_Tick);
this.Loaded += new RoutedEventHandler(timer_Tick);
gutil = new gpsutil();
}
// Load data for the ViewModel Items
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
if (!App.ViewModel.IsDataLoaded)
{
App.ViewModel.LoadData();
}
if (bStart)
{
bStart = false;
isoSto = new IsoStoHandler();
// for testing in emulator
// stores test values in isolated storage
// when building for real device change gensets.TEST_MODE value to false
if (gensets.TEST_MODE)
{
sAprs_data[0] = "OH1xxx-7"; // callsign
sAprs_data[1] = "0000"; // passcode
sAprs_data[2] = "finland.aprs2.net:14580";
sAprs_data[3] = "windows phone test";
sAprs_data[4] = "1"; // polling interval in minutes
sAprs_data[5] = "finland.aprs2.net";
sAprs_data[6] = "14580";
sAprs_data[7] = aprsSym; // aprs symbol, http://wa8lmf.net/aprs/APRS_symbols.htm
isoSto.CreateDataFile(sAprs_data);
}
if (isoSto.ReadDataFile(out sAprs_data[0], out sAprs_data[1], out sAprs_data[2], out sAprs_data[3], out sAprs_data[4], out sAprs_data[5], out sAprs_data[6], out sAprs_data[7]))
{
textBoxConfCallsign.Text = sAprs_data[0];
textBoxConfAPRSpasscode.Text = sAprs_data[1];
textBoxConfAPRS.Text = sAprs_data[2];
textBoxConfName.Text = sAprs_data[3].Trim();
double d = 0;
if (double.TryParse(sAprs_data[4], out d))
{
if (d > 0)
{
sliderConfPollingInt.Value = d;
}
else
{
sliderConfPollingInt.Value = gensets.POLL_INT;
}
}
else
sliderConfPollingInt.Value = gensets.POLL_INT;
Int32.TryParse(sAprs_data[6], out iTcpPort);
}
}
}
private void GetAboutInfo()
{
textBlockAboutCap.Text = gensets.APP_CAP;
textBlockAboutVer.Text = gensets.APP_VERSION;
textBlockAboutC.Text = gensets.APP_COPYRIGHT;
textBlockAboutFirmware.Text = gensets.DEV_FW + DeviceStatus.DeviceFirmwareVersion;
textBlockAboutHW.Text = gensets.DEV_HW + DeviceStatus.DeviceHardwareVersion;
textBlockAboutDevName.Text = gensets.DEV_NAME + DeviceStatus.DeviceName;
textBlockAboutManu.Text = gensets.DEV_MANU + DeviceStatus.DeviceManufacturer;
textBlockAboutOSversion.Text = Environment.OSVersion.ToString();
textBlockAboutCLR.Text = gensets.DEV_CLR + Environment.Version.Major.ToString() + "." + Environment.Version.Minor.ToString() +
gensets.DEV_REV + Environment.Version.Revision.ToString() + gensets.DEV_BUILD + Environment.Version.Build.ToString();
}
private void ClearLocTexts()
{
textBlockLocLat.Text = "";
textBlockLocLon.Text = "";
textBlockLocSpeed.Text = "";
textBlockLocCourse.Text = "";
textBlockLocAlt.Text = "";
textBlockLocTs.Text = "";
textBlockLocHacc.Text = "";
textBlockLocSpc.Text = " ";
textBlockLocSpc2.Text = " ";
}
private void textBoxConfCallsign_TextChanged(object sender, TextChangedEventArgs e)
{
int cursorLocation = textBoxConfCallsign.SelectionStart;
textBoxConfCallsign.Text = textBoxConfCallsign.Text.ToUpper();
textBoxConfCallsign.SelectionStart = cursorLocation;
}
private void slider1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (bSlider)
textBlockConfPollingInt.Text = "Polling interval (" + Math.Round(e.NewValue).ToString() + " minutes)";
}
private void buttonConfSave_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(textBoxConfCallsign.Text.Trim()))
{
MessageBox.Show(gensets.ERR_FLD_MAND);
textBoxConfCallsign.Focus();
return;
}
if (string.IsNullOrEmpty(textBoxConfAPRSpasscode.Text.Trim()))
{
MessageBox.Show(gensets.ERR_FLD_MAND);
textBoxConfAPRSpasscode.Focus();
return;
}
if (string.IsNullOrEmpty(textBoxConfAPRS.Text.Trim()))
{
MessageBox.Show(gensets.ERR_FLD_MAND);
textBoxConfAPRS.Focus();
return;
}
string sTcpPort = string.Empty;
string sAddress = string.Empty;
string sAtcp = textBoxConfAPRS.Text.Trim();
int p = sAtcp.IndexOf(":");
if (p > 0)
{
int l = sAtcp.Length;
if (l > p)
{
sTcpPort = sAtcp.Substring(p + 1, l - p - 1);
sAddress = sAtcp.Substring(0, p);
}
}
if (string.IsNullOrEmpty(sTcpPort))
{
MessageBox.Show(gensets.ERR_NO_TCP_PORT);
textBoxConfAPRS.Focus();
return;
}
int iTempPort;
if (Int32.TryParse(sTcpPort, out iTempPort) == false)
{
MessageBox.Show(gensets.ERR_TCP_PORT_NOT_NUMERIC);
textBoxConfAPRS.Focus();
return;
}
if (string.IsNullOrEmpty(sAddress))
{
MessageBox.Show(gensets.ERR_NO_ADDRESS);
textBoxConfAPRS.Focus();
return;
}
iTcpPort = iTempPort;
sAprs_data[0] = textBoxConfCallsign.Text.Trim();
sAprs_data[1] = textBoxConfAPRSpasscode.Text.Trim();
sAprs_data[2] = textBoxConfAPRS.Text.Trim();
if (string.IsNullOrEmpty(textBoxConfName.Text.Trim()) == false)
sAprs_data[3] = textBoxConfName.Text.Trim();
else
sAprs_data[3] = " ";
sAprs_data[4] = Math.Round(sliderConfPollingInt.Value).ToString();
sAprs_data[5] = sAddress;
sAprs_data[6] = sTcpPort;
sAprs_data[7] = aprsSym;
isoSto.CreateDataFile(sAprs_data);
MessageBox.Show(gensets.DATA_SAVED);
}
private void buttonLocStartStop_Click(object sender, RoutedEventArgs e)
{
ClearLocTexts();
pivotMain.Title = gensets.APP_TITLE;
bool bSettingsOk = true;
if (bIsAprsOn == false)
{
if (string.IsNullOrEmpty(sAprs_data[0]) || string.IsNullOrEmpty(sAprs_data[1]) || string.IsNullOrEmpty(sAprs_data[4]) || string.IsNullOrEmpty(sAprs_data[5]) || string.IsNullOrEmpty(sAprs_data[6]))
{
bSettingsOk = false;
MessageBox.Show(gensets.APRS_NO_SETTINGS);
}
}
CloseConnection();
StopTimer();
if (bIsAprsOn)
{
watcher.Stop();
InitGpsDs();
bPos = false;
bIsAprsOn = false;
buttonLocStartStop.Content = gensets.CONF_START;
}
else
{
bPos = false;
InitGpsDs();
if (watcher.TryStart(false, TimeSpan.FromMilliseconds(gensets.GEO_TIMEOUT)) == true)
{
bIsAprsOn = true;
buttonLocStartStop.Content = gensets.CONF_STOP;
if (bSettingsOk == true)
{
sb.Clear();
sb.Append(gensets.APRS_MSG_SEND_USER);
sb.Append(sAprs_data[0]);
sb.Append(gensets.APRS_MSG_SEND_PASS);
sb.Append(sAprs_data[1]);
sb.Append(gensets.APRS_MSG_SEND_SW);
sb.Append(Environment.NewLine);
strLogin = sb.ToString();
StartTimer();
//CreateConnection();
//if (bConnection == true)
//{
// textBlockLocSpc.Text = gensets.APRS_SERVER_CONN;
// sb.Clear();
// sb.Append(gensets.APRS_MSG_SEND_USER);
// sb.Append(sAprs_data[0]);
// sb.Append(gensets.APRS_MSG_SEND_PASS);
// sb.Append(sAprs_data[1]);
// sb.Append(gensets.APRS_MSG_SEND_SW);
// sb.Append(Environment.NewLine);
// sendData = sb.ToString();
// if (AprsSend(sendData) == true)
// {
// textBlockLocSpc2.Text = sendData;
// StartTimer();
// }
// else
// {
// bConnection = false;
// textBlockLocSpc2.Text = gensets.APRS_SERVER_SEND_ERR_TIMEOUT;
// }
//}
}
}
else
{
MessageBox.Show(gensets.GEO_ERR_TIMEOUT);
}
}
}
private void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
{
dLat = e.Position.Location.Latitude;
dLon = e.Position.Location.Longitude;
dSpeed = e.Position.Location.Speed;
dCourse = e.Position.Location.Course;
//dSpeed = 9;
//dCourse = 9;
bPos = true;
textBlockLocLat.Text = dLat.ToString();
textBlockLocLon.Text = dLon.ToString();
textBlockLocSpeed.Text = Math.Round(dSpeed, 2).ToString() + gensets.LOC_SPEED + " " + Math.Round(dSpeed * 3.6, 2).ToString() + gensets.LOC_SPEED2;
textBlockLocAlt.Text = gensets.LOC_ALT_TXT + Math.Round(e.Position.Location.Altitude).ToString() + gensets.LOC_ALT + " " + gensets.LOC_VACC + Math.Round(e.Position.Location.VerticalAccuracy).ToString() + gensets.LOC_ALT;
textBlockLocCourse.Text = dCourse.ToString() + gensets.LOC_COURSE;
textBlockLocHacc.Text = gensets.LOC_HACC + Math.Round(e.Position.Location.HorizontalAccuracy).ToString() + gensets.LOC_ALT;
textBlockLocTs.Text = e.Position.Timestamp.ToString("dd.MM.yyyy hh:mm:ss");
}
private void CreateConnection()
{
bool bSockConn = true;
CloseConnection();
socketAPRS = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socketAPRS.NoDelay = true;
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.RemoteEndPoint = new DnsEndPoint(sAprs_data[5], iTcpPort);
socketEventArg.Completed += new
EventHandler<SocketAsyncEventArgs>(delegate(object o, SocketAsyncEventArgs e)
{
if (e.SocketError != SocketError.Success)
{
bSockConn = false;
textBlockLocSpc2.Text = gensets.SOCK_ERR + e.SocketError.ToString();
}
done.Set();
});
done.Reset();
socketAPRS.ConnectAsync(socketEventArg);
if (done.WaitOne(gensets.APRS_CONNECT_TIMEOUT))
{
bConnection = true;
}
else
{
bSockConn = false;
textBlockLocSpc.Text = gensets.APRS_SERVER_CONN_ERR_TIMEOUT;
}
if (bSockConn == false)
bConnection = false;
}
private void InitGpsDs()
{
dCourse = Double.NaN;
dSpeed = Double.NaN;
dLat = 0;
dLon = 0;
}
private void CloseConnection()
{
bConnection = false;
if (socketAPRS != null)
{
socketAPRS.Close();
socketAPRS = null;
}
}
private void StartTimer()
{
StopTimer();
bShowLoginStr = true;
timer.Interval = TimeSpan.FromSeconds(double.Parse(sAprs_data[4]) * 60);
timer.Start();
}
private void StopTimer()
{
timer.Stop();
}
void timer_Tick(Object sender, EventArgs args)
{
if (bPos == true)
{
CreateConnection();
if (bConnection == true)
{
textBlockLocSpc.Text = gensets.APRS_SERVER_CONN;
if (AprsSend(strLogin) == true)
{
if (bShowLoginStr)
{
bShowLoginStr = false;
pivotMain.Title = strLogin.Replace(Environment.NewLine, "");
}
}
else
{
bConnection = false;
if (bSocketError == false)
{
textBlockLocSpc2.Text = gensets.APRS_SERVER_SEND_ERR_TIMEOUT;
}
}
}
if (bConnection == true)
{
sb.Clear();
sb.Append(sAprs_data[0]);
sb.Append(gensets.APRS_MSG_SEND_LOC);
sb.Append(gutil.toAprsLat(dLat));
sb.Append("/");
sb.Append(gutil.toAprsLon(dLon));
sb.Append(sAprs_data[7]);
if (dSpeed.Equals(Double.NaN) == false && dCourse.Equals(Double.NaN) == false)
{
sb.Append(gutil.fmtnum(dCourse));
sb.Append("/");
sb.Append(gutil.fmtnum((dSpeed * 3.6) / 1.852));
}
sb.Append(sAprs_data[3]);
sb.Append(Environment.NewLine);
sendData = sb.ToString();
if (AprsSend(sendData) == true)
{
textBlockLocSpc2.Text = sendData.Replace(Environment.NewLine, "");
}
else
{
if (bSocketError == false)
{
textBlockLocSpc2.Text = gensets.APRS_SERVER_SEND_ERR_TIMEOUT;
}
}
}
CloseConnection();
}
}
private bool AprsSend(string strToAprs)
{
textBlockLocSpc2.Text = " ";
bSocketError = false;
if (socketAPRS != null)
{
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.RemoteEndPoint = socketAPRS.RemoteEndPoint;
socketEventArg.UserToken = null;
socketEventArg.Completed += new
EventHandler<SocketAsyncEventArgs>(delegate(object o, SocketAsyncEventArgs e)
{
if (e.SocketError != SocketError.Success)
{
bSocketError = true;
textBlockLocSpc2.Text = gensets.SOCK_ERR + e.SocketError.ToString();
}
done.Set();
});
byte[] byteArr = gutil.StringToAscii(strToAprs);
socketEventArg.SetBuffer(byteArr, 0, byteArr.Length);
done.Reset();
socketAPRS.SendAsync(socketEventArg);
return done.WaitOne(gensets.APRS_SEND_TIMEOUT);
}
return false;
}
}
}
-------------------------------------------------------------------------------------------------------------------------------------------------
IsoStoHandler.cs
using System;
using System.Net;
using System.IO;
using System.IO.IsolatedStorage;
using System.Windows.Resources;
using System.Windows;
namespace wpAPRS
{
public class IsoStoHandler
{
private const string FileName = "wpAPRS_settings.txt";
private const string FolderName = "wpAPRS_app_data";
private string FilePath = System.IO.Path.Combine(FolderName, FileName);
private string[] isoStrData = new string[gensets.ISOSTR_DATA_ROWS];
public void CreateDataFile(string[] strData)
{
CreateNewFile(FilePath, strData);
}
public bool ReadDataFile(out string s1, out string s2, out string s3, out string s4, out string s5, out string s6, out string s7, out string s8)
{
bool b = false;
b = ReadFile(FilePath);
s1 = isoStrData[0];
s2 = isoStrData[1];
s3 = isoStrData[2];
s4 = isoStrData[3];
s5 = isoStrData[4];
s6 = isoStrData[5];
s7 = isoStrData[6];
s8 = isoStrData[7];
return b;
}
public void removeIsoStr()
{
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
store.Remove();
}
}
private void CreateNewFile(string filePath, string[] fdata)
{
//StreamResourceInfo streamResourceInfo = Application.GetResourceStream(new Uri(filePath, UriKind.Relative));
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
string directoryName = System.IO.Path.GetDirectoryName(filePath);
if (!string.IsNullOrEmpty(directoryName) && !myIsolatedStorage.DirectoryExists(directoryName))
{
myIsolatedStorage.CreateDirectory(directoryName);
}
if (myIsolatedStorage.FileExists(filePath))
{
myIsolatedStorage.DeleteFile(filePath);
}
using (IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile(filePath, FileMode.Create, FileAccess.Write))
{
using (StreamWriter writer = new StreamWriter(fileStream))
{
for (int i = 0; i < gensets.ISOSTR_DATA_ROWS; i++)
{
writer.WriteLine(fdata[i]);
}
}
}
}
}
private bool ReadFile(string filePath)
{
int i;
for (i = 0; i < gensets.ISOSTR_DATA_ROWS; i++)
{
isoStrData[i] = string.Empty;
}
bool b = false;
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (myIsolatedStorage.FileExists(filePath))
{
using (IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile(filePath, FileMode.Open, FileAccess.Read))
{
using (StreamReader reader = new StreamReader(fileStream))
{
for (i = 0; i < gensets.ISOSTR_DATA_ROWS; i++)
{
isoStrData[i] = reader.ReadLine();
}
b = true;
}
}
}
//else
//{
// MessageBox.Show(FilePath + " " + GenSets.ERR_FILE_NOT_FOUND);
//}
}
return b;
}
}
}
-------------------------------------------------------------------------------------------------------------------------------------------------
gpsutil.cs
using System;
using System.Net;
namespace wpAPRS
{
public class gpsutil
{
public string toAprsLat(double lat)
{
return toAprsLoc(lat, gensets.LOC_LAT, gensets.LOC_LAT_LEN);
}
public string toAprsLon(double lon)
{
return toAprsLoc(lon, gensets.LOC_LON, gensets.LOC_LON_LEN);
}
// Convert double decimal location to APRS (NMEA) type location
private string toAprsLoc(double loc, string nsew, int len)
{
if (loc >= 0.0)
{
nsew = nsew.Substring(0, 1);
}
else
{
loc = loc * -1;
nsew = nsew.Substring(1, 1);
}
loc += 0.00005;
int locint = Convert.ToInt32(loc);
double locdec = loc - locint;
loc = (locint) * 100 + locdec * 60.0;
string locstr = Convert.ToString(loc) + "0";
int i = locstr.IndexOf(".");
locstr = locstr.Substring(0, i + 3) + nsew;
if (locstr.Length < len)
{
locstr = "0000".Substring(0, len - locstr.Length) + locstr;
}
return locstr;
}
public string fmtnum(double d)
{
d = Math.Floor(d + 0.5);
string s = Convert.ToString(d);
int l = s.Length;
if (l >= 0 && l < 4 && d >= 0)
{
s = "000".Substring(0, 3 - l) + s;
}
else
{
s = "---";
}
return s;
}
public byte[] StringToAscii(string s)
{
byte[] retval = new byte[s.Length];
for (int ix = 0; ix < s.Length; ++ix)
{
char ch = s[ix];
if (ch <= 0x7f) retval[ix] = (byte)ch;
else retval[ix] = (byte)'?';
}
return retval;
}
}
}
-------------------------------------------------------------------------------------------------------------------------------------------------
gensets.cs
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace wpAPRS
{
public static class gensets
{
public const bool TEST_MODE = true; // when building for real device change gensets.TEST_MODE value to false
public const double GEO_TIMEOUT = 2000; //ms
public const string GEO_ERR_TIMEOUT = "GeoCoordinateWatcher timed out on start";
public const int APRS_CONNECT_TIMEOUT = 30000; //ms
public const int APRS_SEND_TIMEOUT = 30000; //ms
public const string APRS_MSG_SEND_USER = "user ";
public const string APRS_MSG_SEND_PASS = " pass ";
public const string APRS_MSG_SEND_SW = " vers wpAPRS 1.0";
public const string APRS_MSG_SEND_LOC = ">APRS,TCPIP*:!";
public const string APRS_SERVER_CONN = "Connected to APRS-IS server";
public const string APRS_SERVER_NO_CONN = "No connection";
public const string APRS_SERVER_CONN_ERR_TIMEOUT = "Connection timeout error";
public const string APRS_SERVER_SEND_ERR_TIMEOUT = "Send to APRS-IS server timeout";
public const string APRS_NO_SETTINGS = "No APRS-IS settings found. Application merely shows GPS data";
public const string SOCK_ERR = "Socket error: ";
public const string APP_TITLE = "APRS";
public const string APP_CAP = "wpAPRS";
public const string APP_VERSION = "Version 1.0";
public const string APP_COPYRIGHT = "(c)";
public const string DEV_FW = "Firmware version ";
public const string DEV_HW = "Hardware version ";
public const string DEV_NAME = "Name: ";
public const string DEV_MANU = "Manufacturer: ";
public const string DEV_CLR = "CLR version ";
public const string DEV_BUILD = " build ";
public const string DEV_REV = " revision ";
public const string LOC_LAT = "NS";
public const string LOC_LON = "EW";
public const int LOC_LAT_LEN = 8;
public const int LOC_LON_LEN = 9;
public const string LOC_SPEED = " m/s";
public const string LOC_SPEED2 = " km/h ";
public const string LOC_ALT = " m";
public const string LOC_HACC = "Horiz. acc. ";
public const string LOC_VACC = "Vert. acc. ";
public const string LOC_ALT_TXT = "Alt. ";
public const string LOC_COURSE = "°";
public const string CONF_START = "Start";
public const string CONF_STOP = "Stop";
public const string ERR_FLD_MAND = "Mandatory field value is missing";
public const string ERR_NO_TCP_PORT = "No TCP port number in APRS-IS server address";
public const string ERR_TCP_PORT_NOT_NUMERIC = "TCP port is not numeric";
public const string ERR_NO_ADDRESS = "Invalid APRS-IS server";
public const string DATA_SAVED = "Configuration settings saved";
public const int ISOSTR_DATA_ROWS = 8;
public const double POLL_INT = 5;
}
}
------------------------------------------------------------------------------------------------------------------------------------
MainPage.xaml
<phone:PhoneApplicationPage
x:Class="wpAPRS.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
d:DataContext="{d:DesignData SampleData/MainViewModelSampleData.xaml}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<!--Pivot Control-->
<controls:Pivot Title="APRS" Name="pivotMain">
<!--Pivot item one-->
<controls:PivotItem Header="Location">
<!--Double line list with text wrapping-->
<StackPanel Height="560" HorizontalAlignment="Left" Margin="10,10,2,2" Name="stackPanelLoc" VerticalAlignment="Top" Width="430">
<TextBlock Height="Auto" Name="textBlockLocLat" Text="lat" HorizontalAlignment="Left" FontSize="40" />
<TextBlock Height="Auto" Name="textBlockLocLon" Text="lon" HorizontalAlignment="Left" FontSize="40" />
<TextBlock Height="Auto" Name="textBlockLocSpeed" Text="spd" HorizontalAlignment="Left" FontSize="32" />
<TextBlock Height="Auto" Name="textBlockLocCourse" Text="course" HorizontalAlignment="Left" FontSize="32" />
<TextBlock Height="Auto" Name="textBlockLocAlt" Text="alt" HorizontalAlignment="Left" FontSize="32" />
<TextBlock Height="Auto" Name="textBlockLocHacc" Text="-" HorizontalAlignment="Left" FontSize="32" />
<TextBlock Height="Auto" Name="textBlockLocTs" Text="-" FontSize="24" />
<TextBlock Height="Auto" Name="textBlockLocSpc2" Text="-" HorizontalAlignment="Left" FontSize="24" TextWrapping="Wrap" />
<TextBlock Height="Auto" Name="textBlockLocSpc" Text="-" HorizontalAlignment="Left" FontSize="24" />
<Button Content="Start" Height="72" Name="buttonLocStartStop" Width="160" HorizontalAlignment="Center" Click="buttonLocStartStop_Click" />
</StackPanel>
</controls:PivotItem>
<!--Pivot item two-->
<controls:PivotItem Header="Configuration" Height="Auto">
<!--Triple line list no text wrapping-->
<StackPanel Height="590" HorizontalAlignment="Left" Margin="2,2,2,2" Name="stackPanelConf" VerticalAlignment="Top" Width="448">
<TextBlock Height="30" Name="textBlockConfCallsign" Text="Callsign (*)" HorizontalAlignment="Left" />
<TextBox Height="72" Name="textBoxConfCallsign" Text="" Width="256" HorizontalAlignment="Left" MaxLength="32" FontSize="25.333" TextChanged="textBoxConfCallsign_TextChanged" />
<TextBlock Height="30" Name="textBlock3" Text="APRS-IS server passcode (*)" HorizontalAlignment="Left" />
<TextBox Height="72" Name="textBoxConfAPRSpasscode" Text="" InputScope="Number" Width="256" HorizontalAlignment="Left" MaxLength="24" FontSize="25.333" />
<TextBlock Height="30" Name="textBlock4" Text="APRS-IS server IP address:port number (*)" HorizontalAlignment="Left" />
<TextBox Height="72" Name="textBoxConfAPRS" Text="" InputScope="Url" Width="440" MaxLength="256" HorizontalAlignment="Left" FontSize="25.333" TextWrapping="Wrap" />
<TextBlock Height="30" Name="textBlock5" Text="Name/comment" HorizontalAlignment="Left" />
<TextBox Height="72" Name="textBoxConfName" Text="" Width="440" HorizontalAlignment="Left" MaxLength="48" TextWrapping="Wrap" FontSize="25.333" />
<TextBlock Height="30" Name="textBlockConfPollingInt" Text="Polling interval (5 minutes)" HorizontalAlignment="Left" />
<Slider Height="86" Name="sliderConfPollingInt" Width="440" Minimum="1" Maximum="60" SmallChange="1" HorizontalAlignment="Left" Value="5" ValueChanged="slider1_ValueChanged" FontSize="20" LargeChange="5" />
<Button Content="Save" Height="72" Name="buttonConfSave" Width="160" Click="buttonConfSave_Click" />
</StackPanel>
</controls:PivotItem>
<!--Pivot item three-->
<controls:PivotItem Header="About">
<StackPanel Height="500" HorizontalAlignment="Left" Margin="10,10,10,10" Name="stackPanelAbout" VerticalAlignment="Top" Width="430">
<TextBlock Height="Auto" Name="textBlockAboutCap" Text="APRS for Windows Phone" HorizontalAlignment="Left" FontSize="32" />
<TextBlock Height="Auto" Name="textBlockAboutVer" Text="Version 1.0" FontSize="32" HorizontalAlignment="Left" />
<TextBlock Height="Auto" Name="textBlockAboutC" Text="(c) " HorizontalAlignment="Left" FontSize="32" TextWrapping="Wrap" />
<TextBlock Height="30" Name="textBlock2" Text=" " HorizontalAlignment="Left" />
<TextBlock Height="30" Name="textBlock1" Text="Device information" HorizontalAlignment="Left" />
<TextBlock Height="30" Name="textBlockAboutOSversion" Text="os version" />
<TextBlock Height="30" Name="textBlockAboutCLR" Text="clr" HorizontalAlignment="Left" />
<TextBlock Height="30" Name="textBlockAboutFirmware" Text="fw" HorizontalAlignment="Left" />
<TextBlock Height="30" Name="textBlockAboutHW" Text="hw" HorizontalAlignment="Left" />
<TextBlock Height="30" Name="textBlockAboutDevName" Text="name" HorizontalAlignment="Left" />
<TextBlock Height="30" Name="textBlockAboutManu" Text="manu" HorizontalAlignment="Left" />
</StackPanel>
</controls:PivotItem>
<!--Pivot item four-->
<controls:PivotItem Header="APRS symbols">
<StackPanel Height="500" HorizontalAlignment="Left" Margin="10,10,10,10" Name="stackPanelSymbols" VerticalAlignment="Top" Width="430">
<Image Height="450" Name="image1" Stretch="Fill" Width="404" Source="/wpAPRS;component/Images/aprsimg.jpg" />
</StackPanel>
</controls:PivotItem>
</controls:Pivot>
</Grid>
<!--Sample code showing usage of ApplicationBar-->
<!--<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton IconUri="appbar.upload.rest.png" Text="Start" x:Name="iconButtonStart" />
<shell:ApplicationBarIconButton IconUri="appbar.stop.rest.png" Text="Stop" x:Name="iconButtonStop" />
<shell:ApplicationBar.MenuItems>
<shell:ApplicationBarMenuItem Text="Get APRS-IS passcode" x:Name="getty" />
</shell:ApplicationBar.MenuItems>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>-->
</phone:PhoneApplicationPage>
Kommentit
Tämän blogin kommentit tarkistetaan ennen julkaisua.