diff --git a/README.md b/README.md
index 2d3cd03ad..e28b8d983 100644
--- a/README.md
+++ b/README.md
@@ -65,6 +65,7 @@ This project is the work of volunteers:
* @NEKLAN: Contributed Japanese translation.
* @Ohcdh: Contributed Irish and Italian translations.
* @Slavino: Contributed Slovak translation.
+* @Zone: Contributed Turkish translation.
Copyright 2019, Geeksville Industries, LLC. GPL V3 license
diff --git a/app/build.gradle b/app/build.gradle
index 5ced5f7df..2c161247a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -35,7 +35,7 @@ android {
defaultConfig {
// We have to list all translated languages here, because some of our libs have bogus languages that google play
// doesn't like and we need to strip them (gr)
- resConfigs "cs", "de", "en", "es", "fi", "fr", "ga", "it", "ja", "nl", "ru", "sk", "sv", "zh"
+ resConfigs "cs", "de", "en", "es", "fi", "fr", "ga", "it", "ja", "nl", "ru", "sk", "sv", "tr", "zh"
// Needed to make mapbox work inside the firebase testlab - FIXME, alas, still doesn't work
ndk {
diff --git a/app/src/main/java/com/geeksville/mesh/service/SoftwareUpdateService.kt b/app/src/main/java/com/geeksville/mesh/service/SoftwareUpdateService.kt
index 6799630a0..cf0c12613 100644
--- a/app/src/main/java/com/geeksville/mesh/service/SoftwareUpdateService.kt
+++ b/app/src/main/java/com/geeksville/mesh/service/SoftwareUpdateService.kt
@@ -9,6 +9,7 @@ import androidx.core.app.JobIntentService
import com.geeksville.android.Logging
import com.geeksville.mesh.MainActivity
import com.geeksville.mesh.R
+import com.geeksville.util.Exceptions
import com.geeksville.util.exceptionReporter
import java.util.*
import java.util.zip.CRC32
@@ -173,21 +174,42 @@ class SoftwareUpdateService : JobIntentService(), Logging {
)
}
+ /**
+ * Convert a version string of the form 1.23.57 to a comparable integer of
+ * the form 12357.
+ *
+ * Or throw an exception if the string can not be parsed
+ */
+ fun verStringToInt(s: String): Int {
+ // Allow 1 to two digits per match
+ val match =
+ Regex("(\\d{1,2}).(\\d{1,2}).(\\d{1,2})").find(s)
+ ?: throw Exception("Can't parse version $s")
+ val (major, minor, build) = match.destructured
+ return major.toInt() * 1000 + minor.toInt() * 100 + build.toInt()
+ }
+
/** Return true if we thing the firmwarte shoulde be updated
+ *
+ * @param swVer the version of the software running on the target
*/
fun shouldUpdate(
context: Context,
swVer: String
- ): Boolean {
- val curver = context.getString(R.string.cur_firmware_version)
+ ): Boolean = try {
+ val curVer = verStringToInt(context.getString(R.string.cur_firmware_version))
+ val minVer =
+ verStringToInt("0.7.8") // The oldest device version with a working software update service
// If the user is running a development build we never do an automatic update
- val isDevBuild = swVer.isEmpty() || swVer == "unset"
+ val deviceVersion =
+ verStringToInt(if (swVer.isEmpty() || swVer == "unset") "99.99.99" else swVer)
- // FIXME, instead compare version strings carefully to see if less than
- val needsUpdate = (curver != swVer)
-
- return needsUpdate && !isDevBuild && false // temporarily disabled because it fails occasionally
+ (curVer > deviceVersion) && (deviceVersion >= minVer)
+ // true
+ } catch (ex: Exception) {
+ Exceptions.report(ex, "Error finding swupdate info")
+ false // If we fail parsing our update info
}
/** Return the filename this device needs to use as an update (or null if no update needed)
@@ -237,71 +259,77 @@ class SoftwareUpdateService : JobIntentService(), Logging {
* you can use it for the software update.
*/
fun doUpdate(context: Context, sync: SafeBluetooth, assetName: String) {
- val service = sync.gatt!!.services.find { it.uuid == SW_UPDATE_UUID }!!
+ try {
+ val g = sync.gatt!!
+ val service = g.services.find { it.uuid == SW_UPDATE_UUID }!!
- info("Starting firmware update for $assetName")
+ info("Starting firmware update for $assetName")
- progress = 0
- val totalSizeDesc = service.getCharacteristic(SW_UPDATE_TOTALSIZE_CHARACTER)
- val dataDesc = service.getCharacteristic(SW_UPDATE_DATA_CHARACTER)
- val crc32Desc = service.getCharacteristic(SW_UPDATE_CRC32_CHARACTER)
- val updateResultDesc = service.getCharacteristic(SW_UPDATE_RESULT_CHARACTER)
+ progress = 0
+ val totalSizeDesc = service.getCharacteristic(SW_UPDATE_TOTALSIZE_CHARACTER)
+ val dataDesc = service.getCharacteristic(SW_UPDATE_DATA_CHARACTER)
+ val crc32Desc = service.getCharacteristic(SW_UPDATE_CRC32_CHARACTER)
+ val updateResultDesc = service.getCharacteristic(SW_UPDATE_RESULT_CHARACTER)
- context.assets.open(assetName).use { firmwareStream ->
- val firmwareCrc = CRC32()
- var firmwareNumSent = 0
- val firmwareSize = firmwareStream.available()
+ context.assets.open(assetName).use { firmwareStream ->
+ val firmwareCrc = CRC32()
+ var firmwareNumSent = 0
+ val firmwareSize = firmwareStream.available()
- // Start the update by writing the # of bytes in the image
- sync.writeCharacteristic(
- totalSizeDesc,
- toNetworkByteArray(firmwareSize, BluetoothGattCharacteristic.FORMAT_UINT32)
- )
+ // Start the update by writing the # of bytes in the image
+ sync.writeCharacteristic(
+ totalSizeDesc,
+ toNetworkByteArray(firmwareSize, BluetoothGattCharacteristic.FORMAT_UINT32)
+ )
- // Our write completed, queue up a readback
- val totalSizeReadback = sync.readCharacteristic(totalSizeDesc)
- .getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32, 0)
- if (totalSizeReadback == 0) // FIXME - handle this case
- throw Exception("Device rejected file size")
+ // Our write completed, queue up a readback
+ val totalSizeReadback = sync.readCharacteristic(totalSizeDesc)
+ .getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32, 0)
+ if (totalSizeReadback == 0) // FIXME - handle this case
+ throw Exception("Device rejected file size")
- // Send all the blocks
- while (firmwareNumSent < firmwareSize) {
- progress = firmwareNumSent * 100 / firmwareSize
- debug("sending block ${progress}%")
- var blockSize = 512 - 3 // Max size MTU excluding framing
+ // Send all the blocks
+ while (firmwareNumSent < firmwareSize) {
+ progress = firmwareNumSent * 100 / firmwareSize
+ debug("sending block ${progress}%")
+ var blockSize = 512 - 3 // Max size MTU excluding framing
- if (blockSize > firmwareStream.available())
- blockSize = firmwareStream.available()
- val buffer = ByteArray(blockSize)
+ if (blockSize > firmwareStream.available())
+ blockSize = firmwareStream.available()
+ val buffer = ByteArray(blockSize)
- // slightly expensive to keep reallocing this buffer, but whatever
- logAssert(firmwareStream.read(buffer) == blockSize)
- firmwareCrc.update(buffer)
+ // slightly expensive to keep reallocing this buffer, but whatever
+ logAssert(firmwareStream.read(buffer) == blockSize)
+ firmwareCrc.update(buffer)
- sync.writeCharacteristic(dataDesc, buffer)
- firmwareNumSent += blockSize
+ sync.writeCharacteristic(dataDesc, buffer)
+ firmwareNumSent += blockSize
+ }
+
+ // We have finished sending all our blocks, so post the CRC so our state machine can advance
+ val c = firmwareCrc.value
+ info("Sent all blocks, crc is $c")
+ sync.writeCharacteristic(
+ crc32Desc,
+ toNetworkByteArray(c.toInt(), BluetoothGattCharacteristic.FORMAT_UINT32)
+ )
+
+ // we just read the update result if !0 we have an error
+ val updateResult =
+ sync.readCharacteristic(updateResultDesc)
+ .getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0)
+ if (updateResult != 0) {
+ progress = -2
+ throw Exception("Device update failed, reason=$updateResult")
+ }
+
+ // Device will now reboot
+
+ progress = -1 // success
}
-
- // We have finished sending all our blocks, so post the CRC so our state machine can advance
- val c = firmwareCrc.value
- info("Sent all blocks, crc is $c")
- sync.writeCharacteristic(
- crc32Desc,
- toNetworkByteArray(c.toInt(), BluetoothGattCharacteristic.FORMAT_UINT32)
- )
-
- // we just read the update result if !0 we have an error
- val updateResult =
- sync.readCharacteristic(updateResultDesc)
- .getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0)
- if (updateResult != 0) {
- progress = -2
- throw Exception("Device update failed, reason=$updateResult")
- }
-
- // Device will now reboot
-
- progress = -1 // success
+ } catch (ex: BLEException) {
+ progress = -3
+ throw ex // Unexpected BLE exception
}
}
}
diff --git a/app/src/main/res/layout/channel_fragment.xml b/app/src/main/res/layout/channel_fragment.xml
index 9a27e3c4b..d2f411259 100644
--- a/app/src/main/res/layout/channel_fragment.xml
+++ b/app/src/main/res/layout/channel_fragment.xml
@@ -20,9 +20,10 @@
android:id="@+id/channelNameEdit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:digits="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890- "
android:hint="@string/channel_name"
android:imeOptions="actionDone"
- android:maxLength="12"
+ android:maxLength="11"
android:singleLine="true"
android:text="@string/unset" />
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 701138484..2a7364a21 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -48,7 +48,7 @@
シェア
切断
スリープ
- 接続済み:%s人中%sオンライン
+ 接続済み:%s人オンライン%s人中
ネットワーク内のノードリスト
ファームウェアアップデート
Meshtasticデバイスに接続しました。(%s)
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
new file mode 100644
index 000000000..3dfccfb5a
--- /dev/null
+++ b/app/src/main/res/values-tr/strings.xml
@@ -0,0 +1,70 @@
+
+
+ Ayarla
+ Kanal Adı
+ Kanal Seçenekleri
+ Paylaş Düğmesi
+ QR kodu
+ Kaldır
+ Bağlantı durumu
+ uygulama ikonu
+ Bilinmeyen kullanıcı adı
+ Avatar
+ hey I found the cache, it is over here next to the big tiger. I\'m kinda scared.
+ Metni Gönder
+ Telefonu, henüz Meshtastic uyumlu bir telsiz ile eşleştirmediniz. Bir cihazla eşleştirin ve kullanıcı adınızı belirleyin lütfen.\n\nAçık kaynaklı bu uygulama şu an alfa-test\'i aşamasında, problemler görürseniz forum\'da lütfen paylaşınız: meshtastic.discourse.group.\n\nDaha fazla bilgi için internet sitemizi ziyaret ediniz - www.meshtastic.org.
+ Kullanıcı adını kaldır
+ Adınız
+ Anonim kullanim istatistikleri ve hata raporları.
+ Meshtastic cihazları aranıyor...
+ Bu cihaz bluetooth erişimi gerektiriyor. Lütfen Android ayarlarından izin veriniz.
+ Hata - bu uygulama bluetooth gerektiriyor
+ Eşleşme başlatılıyor
+ Eşleşme başarız
+ Meshtastic mesh ağına bağlanmak için adres
+ Kabul et
+ İptal
+ Kanalı değiştir
+ Kanalı değiştirmek istediğinize emin misiniz? Yeni kanal ayarlarını paylaşana dek tüm node\'lar ile iletişim sonlanacak.
+ Yeni Kanal Adresi alındı
+ \'%s\' kanalına geçmek istiyor musunuz?
+ Analitik raporları kapattınız. Harita sağlayıcımız (mapbox) ücretsiz kullanım paketi için analitik raporları gerektiriyor maalesef. Bu yüzden harita görünümü pasif hale getirdik.\n\n
+ Haritayı görmek istiyorsanız, Ayarlar bölümünden analitik raporları aktif hale getirmeniz gerekiyor. (ayrıca, şu an bunun için uygulamayı tümüyle kapatıp yeniden açmanız gerekebilir).\n\n
+ Eğer mapbox için ödeme yapmamız (ya da başka bir harita sağlayıcıya geçme) konusunda ilgiliyseniz, lütfen meshtastic.discourse.group sayfasında paylaşınız.
+ Gerekli bir izin eksik, Meshtastic düzgün çalışamayacak. Lütfen Android ayarlarından izni aktif hale getiriniz.
+ Telsiz uyku durumundaydı, kanal değiştirilemedi
+ Hata Bildir
+ Hata Bildir
+ Hata bildirmek istediğinizden emin misiniz? Hata bildirdikten sonra, lütfen meshtastic.discourse.group sayfasında paylaşınız ki raporu bulgularınızla eşleştirebilelim.
+ Bildir
+ Telsiz seçiniz
+ Şu anda %s telsizi ile eşleşmiş durumdasınız.
+ Henüz bir telsiz ile eşleşmediniz.
+ Telsizi değiştir
+ Cihazı Android ayarlarında eşleştiriniz lütfen.
+ Eşleşme tamamlandı, servis başlatılıyor
+ Eşleşme başarısız, lütfen tekrar seçiniz
+ Konum erişimi kapalı, konum mesh ağına paylaşılamıyor.
+ Paylaş
+ Bağlantı sonlandı
+ Cihaz uyku durumunda
+ Bağlandı: %s / %s online
+ Ağdaki node listesi
+ Yazılım güncelle
+ Radyoya bağlandı
+ (%s) telsizine bağlandı
+ Bağlı değil, aşağıdan bir radyo seçiniz
+ Telsize bağlandı, ancak uyku durumunda
+ %s\'e güncelle
+ Uygulama çok eski
+ Uygulamayı Google Play store (ya da GitHub)\'da güncellemelisiniz. Bu telsiz ile haberleşmek için uygualama çok eski.
+ Hiçbiri (kapat)
+ Kısa menzilli (ama hızlı)
+ Orta menzilli (ama hızlı)
+ Uzun menzilli (ama yavaş)
+ Çok uzun menzilli (ama yavaş)
+ TANIMLANAMADI
+ Meshtastic Servis Bildirimleri
+ Android ayarlarında konum servislerine izin vermelisiniz
+ Hakkında
+
\ No newline at end of file