I am intending to perform FSK demodulation and came across the Androino Project(https://code.google.com/p/androino/source/browse/wiki/AndroinoTerminal.wiki), which reads in data from the Adruino into the phone's audio jack, which is pretty darn cool.
I am trying to go through the code but I can't make sense of some impt values. :((
Why is the bit-high = 22 peaks, bit-low = 6 peaks, private static int HIGH_BIT_N_PEAKS = 12 and private static int LOW_BIT_N_PEAKS = 7?? And why is it 136 samples per encoded bit?
Am I also right to say that the FSK rate of the Adruino is set at 315Hz?
I have attached the hardware(softTerm) codes as well: https://code.google.com/p/androino/source/browse/trunk/arduino/SoftTerm/SoftModem/SoftModem.h and the cpp file is in there as well. Dun have enough reputation points to post both links.
/** Copyright (C) 2011 Androino authors
Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.androino.ttt;
import android.util.Log;
public class FSKModule {
// Experimental results
// Arduino sends "a" character (97) 1100001
// The generated message is 0110.0001
// 136 samples per encoded bit
// total message = 166 bits: 155(high)+1(low)+8bit+stop(high)+end(high)
private static int SAMPLING_FREQUENCY = 44100; //Hz
private static double SAMPLING_TIME = 1.0/SAMPLING_FREQUENCY; //ms
// reading zero+155(high)+1(low)+8bit+stop+end+zero
private static int FREQUENCY_HIGH = 3150;
private static int FREQUENCY_LOW = 1575;
//high: 7 samples/peak
//low : 14 samples/peak
// 1492 samples/message low+8bits+stop+end
// 136 samples/bit (=1492/11)
private static int SAMPLES_PER_BIT = 136;
private static int ENCODING_SAMPLES_PER_BIT = SAMPLES_PER_BIT/2; // 68
// bit-high = 22 peaks
// bit-low = 6 peaks
private static int HIGH_BIT_N_PEAKS = 12;
private static int LOW_BIT_N_PEAKS = 7;
private static int SLOTS_PER_BIT = 4; // 4 parts: determines the size of the part analyzed to count peaks
private static int N_POINTS = SAMPLES_PER_BIT/SLOTS_PER_BIT; // 34=136/4
private static double PEAK_AMPLITUDE_TRESHOLD = 60; // significant sample (not noise)
private static int NUMBER_SAMPLES_PEAK = 4; // minimum number of significant samples to be considered a peak
private static int MINUMUM_NPEAKS = 100; // if lower it means that there is no signal/message
private static final int BIT_HIGH_SYMBOL=2;
private static final int BIT_LOW_SYMBOL=1;
private static final int BIT_NONE_SYMBOL=0;
private static final int CARRIER_MIN_HIGH_BITS=12;
private static final int SOUND_AMPLITUDE = 31000;
private static final String TAG = "FSKModule";
private FSKModule(){
}
private static void debugInfo(String message){
//System.out.println(">>" + message);
Log.w(TAG, "FSKDEC:"+ message);
}
//-----------------------------------------
// DECODING FUNCTIONS
//-----------------------------------------
public static boolean signalAvailable(double[] sound){
FSKModule m = new FSKModule();
int nPoints = N_POINTS;
int nParts = sound.length / nPoints;
int nPeaks = 0;
int startIndex = 0;
int i = 0;
do {
int endIndex = startIndex + nPoints;
int n = m.countPeaks(sound, startIndex, endIndex);
nPeaks += n;
i++;
startIndex = endIndex;
if (nPeaks > MINUMUM_NPEAKS) return true;
} while (i<nParts);
if (nPeaks >3)
debugInfo("signalAvailable() nPeaks=" + nPeaks);
return false;
}
public static int decodeSound(double[] sound){
FSKModule m = new FSKModule();
// processing sound in parts and
//Log.w(TAG, "ENTRO EN processSound");
int[] nPeaks = m.processSound(sound);
if (nPeaks.length == 0) // exit: no signal detected
return -1;
//debugInfo("decodeSound nPeaks=" + nPeaks.length);
// transform number of peaks into bits
//Log.w(TAG, "ENTRO EN parseBits");
int[] bits = m.parseBits(nPeaks);//-------------------------> OK!!
//debugInfo("decodeSound nBits=" + bits.length);
// extract message from the bit array
int message = m.decodeUniqueMessage(bits, sound, nPeaks);
debugInfo("decodeSound(): message="+message + ":" + Integer.toBinaryString(message));
return message;
}
private int decodeUniqueMessageCorrected(int[] nPeaks, int startBit){
int message = 0;
// process nPeaks starting from the end
int index = (startBit+12)*SLOTS_PER_BIT;
// find zero -> non zero transition
for (int i = 0; i < index; i++) {
int i2 = nPeaks[index-i];
int i1 = nPeaks[index-i-1];
debugInfo("zero->nonzero index=" + (index-i) + ": i2=" + i2 + ":i1=" + i1);
if ( (i1-i2)>2) {
index = index-i-1;
break;
}
}
debugInfo("zero->nonzero index=" + index);
int[] bits = new int[2+8+1+2];
for (int i = 0; i < bits.length; i++) {
int peakCounter = 0;
for (int j = 0; j < 4; j++) {
peakCounter += nPeaks[index-j];
}
debugInfo("decode corrected: peakCounter="+i + ":" + peakCounter);
if (peakCounter > 7) { //LOW_BIT_N_PEAKS)
bits[i] = BIT_LOW_SYMBOL;
}
if (peakCounter > 12) { //LOW_BIT_N_PEAKS)
bits[i] = BIT_HIGH_SYMBOL;
message += Math.pow(2, i);
}
debugInfo("bit=" + bits[i] + ":" + message);
index = index -4;
}
debugInfo("decode corrected: message="+message + ":" + Integer.toBinaryString(message));
message = 0;
for (int i = 2; i < 10; i++) {
if ( bits[i] == BIT_HIGH_SYMBOL) {
message+= Math.pow(2, 7-(i-2));
}
}
return message;
}
private int decodeUniqueMessage(int[] bits, double[] sound, int[] nPeaks){
// start bit
int index = findStartBit(bits, 0);
debugInfo("decodeUniqueMessage():start bit=" + index);
if (index == -1) return -1; // no start-bit detected
if (index + 8 + 2 > bits.length)
throw new AndroinoException("Message cutted, start bit at " + index, AndroinoException.TYPE_FSK_DECODING_ERROR);
// debugging information
int number = 16; // n bits to debug
for (int i = index-5; i < index-5+number; i++) {
debugInfo("decodeUniqueMessage(): bits=" + i +":" + bits[i] );
}
for (int i = 0; i < number*SLOTS_PER_BIT; i++) {
int position = i + (index-5)*SLOTS_PER_BIT ;
debugInfo("decodeUniqueMessage(): npeaks=" + position+ ":" + nPeaks[position] );
}
// 8bits message
int value = 0;
for (int i = 0; i < 8; i++) {
int bit = bits[index+i];
if (bit==BIT_HIGH_SYMBOL) value+=Math.pow(2, i);
}
// stop bit: do nothing
// end bit: do nothing
debugInfo("MESSAGE =" + Integer.toBinaryString(value) + ":" + value);
*/
int correctedMessage = decodeUniqueMessageCorrected(nPeaks,index);
debugInfo("MESSAGE corrected=" + Integer.toBinaryString(correctedMessage) + ":" + correctedMessage);
return correctedMessage;
}
private int findStartBit(int[] bits, int startIndex){
// find carrier and start bit
int index = startIndex;
int highCounter = 0;
boolean startBitDetected = false;
do {
int bit = bits[index];
switch (bit) {
case BIT_HIGH_SYMBOL:
highCounter++; // carrier high bit
break;
case BIT_LOW_SYMBOL:
if (highCounter>CARRIER_MIN_HIGH_BITS) { // start-bit detected
startBitDetected = true;
}
else highCounter = 0; // reset carrier counter
break;
case BIT_NONE_SYMBOL:
highCounter = 0;// reset carrier counter
break;
}
index++;
if (index>=bits.length) return -1;
} while (!startBitDetected);
return index;
}
private int[] parseBits(int[] peaks){
// from the number of peaks array decode into an array of bits (2=bit-1, 1=bit-0, 0=no bit)
//
int i =0;
int lowCounter = 0;
int highCounter = 0;
int nBits = peaks.length /SLOTS_PER_BIT;
int[] bits = new int[nBits];
//i = findNextZero(peaks,i); // do not search for silence
i = findNextNonZero(peaks,i);
int nonZeroIndex = i;
if (i+ SLOTS_PER_BIT >= peaks.length) //non-zero not found
return bits;
do {
//int nPeaks = peaks[i]+peaks[i+1]+peaks[i+2]+peaks[i+3];
int nPeaks = 0;
for (int j = 0; j < SLOTS_PER_BIT; j++) {
nPeaks+= peaks[i+j];
}
int position = i/SLOTS_PER_BIT;
bits[position] = BIT_NONE_SYMBOL;
debugInfo("npeaks:i=" + i + ":pos=" + position+ ": nPeaks=" + nPeaks);
if (nPeaks>= LOW_BIT_N_PEAKS) {
//Log.w(TAG, "parseBits NPEAK=" + nPeaks);
bits[position] = BIT_LOW_SYMBOL;
lowCounter++;
}
if (nPeaks>=HIGH_BIT_N_PEAKS ) {
bits[position] = BIT_HIGH_SYMBOL;
highCounter++;
}
//if (nPeaks>5) bits[position] = 1;
//if (nPeaks>12) bits[position] = 2;
i=i+SLOTS_PER_BIT;
} while (SLOTS_PER_BIT+i<peaks.length);
lowCounter = lowCounter - highCounter;
debugInfo("parseBits nonZeroIndex=" + nonZeroIndex);
debugInfo("parseBits lows=" + lowCounter);
debugInfo("parseBits highs=" + highCounter);
return bits;
}
private int findNextNonZero(int[] peaks, int startIndex){
// returns the position of the next value != 0 starting form startIndex
int index = startIndex;
int value = 1;
do {
value = peaks[index];
index++;
} while (value==0 && index<peaks.length-1);
return index-1;
}
private int[] processSound(double[] sound){
// split the sound array into slots of N_POINTS and calculate the number of peaks
int nPoints = N_POINTS;
int nParts = sound.length / nPoints;
int[] nPeaks = new int[nParts];
int startIndex = 0;
int i = 0;
int peakCounter = 0;
do {
int endIndex = startIndex + nPoints;
int n = this.countPeaks(sound, startIndex, endIndex);
nPeaks[i] = n;
peakCounter += n;
i++;
startIndex = endIndex;
} while (i<nParts);
//} while (startIndex+nPoints<sound.length);
debugInfo("processSound() peaksCounter=" + peakCounter);
if (peakCounter < MINUMUM_NPEAKS) {
nPeaks = new int[0];
}
return nPeaks;
}
private int countPeaks(double[] sound, int startIndex, int endIndex){
// count the number of peaks in the selected interval
// peak identification criteria: sign changed and several significant samples (>PEAK_AMPLITUDE_TRESHOLD)
int index = startIndex;
int signChangeCounter = 0;
int numberSamplesGreaterThresdhold = 0;
int sign = 0; // initialized at the first significant value
do {
double value = sound[index];
if (Math.abs(value)>PEAK_AMPLITUDE_TRESHOLD)
numberSamplesGreaterThresdhold++; //significant value
// sign initialization: take the sign of the first significant value
if (sign==0 & numberSamplesGreaterThresdhold>0) sign = (int) (value / Math.abs(value));
boolean signChanged = false;
if (sign <0 & value >0) signChanged = true;
if (sign >0 & value <0) signChanged = true;
if (signChanged & numberSamplesGreaterThresdhold>NUMBER_SAMPLES_PEAK){
signChangeCounter++; // count peak
sign=-1*sign; //change sign
}
index++;
//debugInfo(">>>>>>>index=" + index + " sign=" + sign + " signChangeCounter=" + signChangeCounter + " value=" + value + " numberSamplesGreaterThresdhold=" + numberSamplesGreaterThresdhold);
} while (index<endIndex);
return signChangeCounter;
}
}
Related
When I run the game using unity I get this error continuously in the console window and the loading screen is not going further next. Help me to fix this issue.
IndexOutOfRangeException: Array index is out of range.
DataCache.GetAchievementCacheData () (at
Assets/Scripts/Mission/Plugin/DataCache.cs:329)
Here is my code below
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using UnityEngine;
//Class luu mission current
public class CurrentMission
{
public string FB_id { get; set; }
public string Name { get; set; }
public string Mission { get; set; }
public CurrentMission(string id, string name, string mission)
{
this.FB_id = id;
this.Name = name;
this.Mission = mission;
}
public CurrentMission()
{
this.FB_id = "";
this.Name = "";
this.Mission = "";
}
}
public class MissionDataSave
{
public int Mission;
public long Score;
public int Star;
public int Open;//0-false. 1-true
public MissionDataSave(int mission, long score, int star, int open)
{
Mission = mission;
Score = score;
Star = star;
Open = open;
}
public MissionDataSave()
{
Mission = 0;
Score = 0;
Star = 0;
Open = 0;
}
}
public class AchievementCache
{
//group nhiem vu
public int Group;
//Level hien tai cua group
public int Level;
//Gia tri hien tai
public int Value;
//Thong bao mission hoan thanh
public int Notify;//0 - False, 1 - true
//public AchievementCache()
//{
// this.Group = 1;
// this.Level = 1;
// this.Value = 0;
//}
public AchievementCache(int group, int level, int value, int notify)
{
this.Group = group;
this.Value = value;
this.Level = level;
this.Notify = notify;
}
public AchievementCache()
{
this.Group = 1;
this.Value = 0;
this.Level = 1;
this.Notify = 0;
}
}
public class DataCache
{
public static string FB_ID = "FB_ID";
public static string FB_USER = "FB_USER";
public static string Achievement_data_key = "Achievement_data_key";
public static string Mission_data_key = "Mission_data_key";
public static string Current_mission_data_key = "Current_mission_data_key";
public static AchievementCache[] dataAchievementCache;
public static MissionDataSave[] dataMissionCache;
public static CurrentMission[] dataCurrentMissionCache;
//public static string XML_Current_Mission_Path = "CurrentMissionSave.xml";
//public static string XML_Data_Mission_Path = "DataMissionSave.xml";
//public static string XML_Data_Achievement_Path = "AchievementCache.xml";
//serialize xml theo tung phan tu
//public static List<MissionDataSave> DeserializeMissionDataSaveListFromXML(string filePath)
//{
// if (!System.IO.File.Exists(filePath))
// {
// Debug.LogError("File " + filePath + " not exist!");
// return new List<MissionDataSave>();
// }
// XmlSerializer deserializer = new XmlSerializer(typeof(List<MissionDataSave>), new XmlRootAttribute("MissionDataSaveRoot"));
// TextReader textReader = new StreamReader(filePath);
// List<MissionDataSave> movies = (List<MissionDataSave>)deserializer.Deserialize(textReader);
// textReader.Close();
// return movies;
//}
//public static void readXMLTest()
//{
// string xmlDataCache1 = Application.persistentDataPath + "/" + XML_Current_Mission_Path;
// TextReader textReader = new StreamReader(xmlDataCache1);
// XmlDocument xmlDoc = new XmlDocument();
// xmlDoc.Load(textReader);
// XmlNodeList xmlNodeList = xmlDoc.DocumentElement.ChildNodes;
// Debug.Log("TRUOC");
// foreach (XmlNode node in xmlNodeList)
// {
// Debug.Log("aaaaaaaaaaaaaaaaaaaaa " + node.Attributes["Id"].Value);
// }
// Debug.Log("SAU");
// XmlNode root = xmlDoc.DocumentElement;
// XmlElement elem = xmlDoc.CreateElement("CurrentMissionCache");
// elem.SetAttribute("Id", "112312");
// elem.SetAttribute("Name", "NameDG");
// elem.SetAttribute("Mission", "MissionDG");
// root.AppendChild(elem);
// textReader.Close();
// xmlDoc.Save(xmlDataCache1);
//}
//Add mission xml node
public static void UpdateMissionScore(long score, int star, int mission, int open)
{
MissionDataSave data = dataMissionCache[mission - 1];
if (data.Star < star)
{
data.Star = star;
}
if (data.Score < score)
{
data.Score = score;
}
data.Open = open;
}
public static void SaveMissionDataCache(bool submitToServer = false)
{
string dataSave = "";
string dataSendServer = "";
for (int i = 0; i < dataMissionCache.Length; i++)
{
dataSave += dataMissionCache[i].Mission + "-" + dataMissionCache[i].Score + "-" + dataMissionCache[i].Star + "-" + dataMissionCache[i].Open + ",";
//Chi gui nhung mission da open len server
if (dataMissionCache[i].Open == 1)
{
if (dataSendServer.Length > 0)
dataSendServer += ",";
dataSendServer += dataMissionCache[i].Mission + "-" + dataMissionCache[i].Score + "-" + dataMissionCache[i].Star + "-" + dataMissionCache[i].Open;
}
}
Debug.Log("Data save " + dataSave);
PlayerPrefs.SetString(Mission_data_key, dataSave);
if (submitToServer)
{
Debug.Log("Data send server " + dataSendServer);
AudioControl.getMonoBehaviour().StartCoroutine(DHS.PostMeInfoMissionUpdate(FB.UserId, dataSendServer));
}
}
public static void GetMissionDataCache()
{
int max_mission = 100;
if (dataMissionCache != null)
{
dataMissionCache = null;
}
dataMissionCache = new MissionDataSave[max_mission];
//Tao moi neu chua co
if (!PlayerPrefs.HasKey(Mission_data_key))
{
string datas = "1-0-0-1,";
for (int i = 2; i <= max_mission; i++)
{
//Mission - Score - Star - Open
if (DataMissionControlNew.test)
{
datas += i + "-0-0-1,";
//if (i < 16)
// datas += i + "-0-0-1,";
//else datas += i + "-0-0-0,";
}
else
{
datas += i + "-0-0-0,";
}
}
PlayerPrefs.SetString(Mission_data_key, datas);
}
string missionData = PlayerPrefs.GetString(Mission_data_key);
string[] data = missionData.Split(',');
for (int i = 0; i < max_mission; i++)
{
string[] infoData = data[i].Split('-');
//Debug.Log("Info " + data[i]);
string mission = infoData[0];
string score = infoData[1];
string star = infoData[2];
string open = infoData[3];
dataMissionCache[i] = new MissionDataSave(Convert.ToUInt16(mission), Convert.ToUInt32(score), Convert.ToUInt16(star), Convert.ToUInt16(open));
}
}
//-------------------------CURRENT MISSION---------------------------
//Add current mission xml node
public static void SaveCurrentMission(string data = "")
{
if (String.IsNullOrEmpty(data))
{
string dataSave = "";
for (int i = 0; i < dataCurrentMissionCache.Length; i++)
{
if (dataSave.Length > 0)
dataSave += ",";
dataSave += dataCurrentMissionCache[i].FB_id + "-" + dataCurrentMissionCache[i].Name + "-" + dataCurrentMissionCache[i].Mission;
}
PlayerPrefs.SetString(Current_mission_data_key, dataSave);
}
else
{
PlayerPrefs.SetString(Current_mission_data_key, data);
GetCurrentMission();
}
}
public static void GetCurrentMission()
{
if (!PlayerPrefs.HasKey(Current_mission_data_key))
{
PlayerPrefs.SetString(Current_mission_data_key, "Me-User-1");
}
if (dataCurrentMissionCache != null)
{
dataCurrentMissionCache = null;
}
string current_data = PlayerPrefs.GetString(Current_mission_data_key);
string[] data = current_data.Split(',');
dataCurrentMissionCache = new CurrentMission[data.Length];
for (int i = 0; i < data.Length; i++)
{
string[] info = data[i].Split('-');
//fb - User name - missison
dataCurrentMissionCache[i] = new CurrentMission(info[0], info[1], info[2]);
}
}
public static void SetMeCurrentMission(int mission)
{
for (int i = 0; i < DataCache.dataCurrentMissionCache.Length; i++)
{
if ("Me".Equals(DataCache.dataCurrentMissionCache[i].FB_id))
{
int old = Convert.ToInt16(DataCache.dataCurrentMissionCache[i].Mission);
if (old < mission)
{
DataCache.dataCurrentMissionCache[i].Mission = "" + mission;
DataCache.UpdateMissionScore(0, 0, mission, 1);//Them mission moi vao xml
}
}
}
DataCache.SaveCurrentMission();
}
//-------------------------ACHIEVEMENT---------------------------
//Ghi de len du lieu cu
public static void ReplaceAchievementCache(int groupLevel, int value, int level = -1)
{
dataAchievementCache[groupLevel - 1].Value = value;
if (level != -1)
{
dataAchievementCache[groupLevel - 1].Level = level;
}
}
//Cap nhat them du lieu
public static void AddAchievementCache(int groupLevel, int addValue, int addLevel = 0)
{
dataAchievementCache[groupLevel - 1].Level += addLevel;
dataAchievementCache[groupLevel - 1].Value += addValue;
}
public static void GetAchievementCacheData()
{
Debug.Log("-------------GetAchievementCacheData--------------------");
if (dataAchievementCache != null)
{
dataAchievementCache = null;
}
dataAchievementCache = new AchievementCache[22];
//Tao achievement
if (!PlayerPrefs.HasKey(Achievement_data_key))
{
string achi = "";
for (int i = 1; i <= 22; i++)
{
achi += i + "-1-0-0,";
}
//Debug.Log("Create new achievement " + achi);
PlayerPrefs.SetString(Achievement_data_key, achi);
}
string achievement = PlayerPrefs.GetString(Achievement_data_key);
//Debug.Log(achievement);
string[] achie = achievement.Split(',');
for (int i = 0; i< dataAchievementCache.Length; i++)
{
//Debug.Log(achie[i]);
string[] infoAchie = achie[i].Split('-');
string group = infoAchie[0];
string level = infoAchie[1];
string value = infoAchie[2];
string notify = infoAchie[3];
//Debug.Log(group +" " + dataAchievementCache[i].Group);
dataAchievementCache[i] = new AchievementCache();
dataAchievementCache[i].Group = Convert.ToInt16(group);
dataAchievementCache[i].Level = Convert.ToInt16(level);
dataAchievementCache[i].Value = Convert.ToInt32(value);
dataAchievementCache[i].Notify = Convert.ToInt16(notify);
}
}
public static void SaveAchievementCache(bool sendServer = false)
{
try
{
Debug.Log("-------------------SaveAchievementCache-----------------");
if (dataAchievementCache != null)
{
string achievement = "";
for (int i = 0; i < dataAchievementCache.Length; i++)
{
string s = "" + dataAchievementCache[i].Group + "-" + dataAchievementCache[i].Level + "-" + dataAchievementCache[i].Value + "-" + dataAchievementCache[i].Notify + ",";
achievement += s;
}
//Debug.Log("----------LUU ACHIEVEMENT------------ " + achievement);
PlayerPrefs.SetString(Achievement_data_key, achievement);
if (FB.IsLoggedIn && sendServer)
{
//Nếu chưa có playerprefs thì sẽ submit lên luôn
//Nếu có rồi thì phải check nó cập nhật hoàn thành từ server về thì mới cho up lên
bool check = !PlayerPrefs.HasKey(DataMissionControlNew.key_update_achievement_data_from_server) ||
(PlayerPrefs.HasKey(DataMissionControlNew.key_update_achievement_data_from_server) && PlayerPrefs.GetInt(DataMissionControlNew.key_update_achievement_data_from_server) == 1);
if (check)
{
AudioControl.getMonoBehaviour().StartCoroutine(DHS.PostMeInfoUpdate(DFB.UserId, "" + VariableSystem.diamond, "" + achievement, "", (www) =>
{
Debug.Log("----------Update achievement to server success!------------- " + achievement);
}));
}
else
{
Debug.Log("----------KHONG CHO UP ACHIEVEMENT VA DIAMOND LEN SERVER------------- " + PlayerPrefs.GetInt(DataMissionControlNew.key_update_mission_data_from_server, 0));
}
}
}
}
catch (Exception e)
{
Debug.Log("------------ERROR ---------------" + e.Message);
if (DataMissionControlNew.test)
{
MobilePlugin.getInstance().ShowToast("ERROR " + e.Message);
}
}
}
public static void DeleteUserData()
{
PlayerPrefs.DeleteKey(FB_ID);
PlayerPrefs.DeleteKey(Mission_data_key);
PlayerPrefs.DeleteKey(Current_mission_data_key);
PlayerPrefs.DeleteKey(Achievement_data_key);
PlayerPrefs.DeleteKey("diamond");
PlayerPrefs.DeleteKey(DataMissionControlNew.key_update_mission_data_from_server);
VariableSystem.diamond = 8;
VariableSystem.heart = 5;
}
public static void RestoreUserData(int diamond, string achievement)
{
Debug.Log("Restore user data");
VariableSystem.diamond = diamond;
VariableSystem.heart = PlayerPrefs.GetInt("heart", 5);
string[] achie = achievement.Split(',');
if (achie.Length > 5)
{
for (int i = 0; i < dataAchievementCache.Length; i++)
{
string[] infoAchie = achie[i].Split('-');
string group = infoAchie[0];
string level = infoAchie[1];
string value = infoAchie[2];
string notify = infoAchie[3];
dataAchievementCache[i].Group = Convert.ToInt16(group);
dataAchievementCache[i].Level = Convert.ToInt16(level);
dataAchievementCache[i].Value = Convert.ToInt32(value);
dataAchievementCache[i].Notify = Convert.ToInt16(notify);
}
//Debug.Log("---Luu achievement----");
SaveAchievementCache();
GetAchievementCacheData();
}
Debug.Log("----------------ACHIEVEMENT da dc cap nhat tu -----------------");
PlayerPrefs.SetInt(DataMissionControlNew.key_update_achievement_data_from_server, 1);
}
The line 329 is this
string level = infoAchie[1];
The problem is coming from the last comma you are adding in the string you are adding to your PlayerPrefs in this part:
if (!PlayerPrefs.HasKey(Achievement_data_key))
{
string achi = "";
for (int i = 1; i <= 22; i++)
{
achi += i + "-1-0-0,";
}
//Debug.Log("Create new achievement " + achi);
PlayerPrefs.SetString(Achievement_data_key, achi);
}
This code generates this string:
1-1-0-0,2-1-0-0,3-1-0-0,4-1-0-0,5-1-0-0,6-1-0-0,7-1-0-0,8-1-0-0,9-1-0-0,10-1-0-0,11-1-0-0,12-1-0-0,13-1-0-0,14-1-0-0,15-1-0-0,16-1-0-0,17-1-0-0,18-1-0-0,19-1-0-0,20-1-0-0,21-1-0-0,22-1-0-0,
Keep in memory that last comma at the end of the string.
You are later doing a split on the ',' character, and iterating over them.
string[] achie = achievement.Split(',');
for (int i = 0; i< dataAchievementCache.Length; i++)
{
//Debug.Log(achie[i]);
string[] infoAchie = achie[i].Split('-');
string group = infoAchie[0];
string level = infoAchie[1];
...
}
The problem is that by doing so, your achie string array contains an empty last element. So when you are later splitting on the "-" character, your infoAchie string array only contains one element: the empty string. The first line:
string group = infoAchie[0];
Still works, but is filled with the empty string. Then:
string level = infoAchie[1];
Can't work, as you are indeed out of the bounds of the infoAchie array.
The solution would be to add the comma to your string only if it is not the last element.
Also, I strongly advise you to use a StringBuilder over a simple string for optimization purposes. Your code could then look like, for instance:
if (!PlayerPrefs.HasKey(Achievement_data_key))
{
StringBuilder achi = new StringBuilder();
for (int i = 1; i <= 22; i++)
{
achi.Append(i).Append("-1-0-0");
if(i != 22)
achi.Append(",");
}
//Debug.Log("Create new achievement " + achi);
PlayerPrefs.SetString(Achievement_data_key, achi.ToString());
}
Which generates this string:
1-1-0-0,2-1-0-0,3-1-0-0,4-1-0-0,5-1-0-0,6-1-0-0,7-1-0-0,8-1-0-0,9-1-0-0,10-1-0-0,11-1-0-0,12-1-0-0,13-1-0-0,14-1-0-0,15-1-0-0,16-1-0-0,17-1-0-0,18-1-0-0,19-1-0-0,20-1-0-0,21-1-0-0,22-1-0-0
How to compare app version in android
I got latest version code and current version code , but the problem is
current version is 1.0
and latest version is 1.0.0
so how to compare that float value in android
I have written a small Android library for comparing version numbers: https://github.com/G00fY2/version-compare
What it basically does is this:
public int compareVersions(String versionA, String versionB) {
String[] versionTokensA = versionA.split("\\.");
String[] versionTokensB = versionB.split("\\.");
List<Integer> versionNumbersA = new ArrayList<>();
List<Integer> versionNumbersB = new ArrayList<>();
for (String versionToken : versionTokensA) {
versionNumbersA.add(Integer.parseInt(versionToken));
}
for (String versionToken : versionTokensB) {
versionNumbersB.add(Integer.parseInt(versionToken));
}
final int versionASize = versionNumbersA.size();
final int versionBSize = versionNumbersB.size();
int maxSize = Math.max(versionASize, versionBSize);
for (int i = 0; i < maxSize; i++) {
if ((i < versionASize ? versionNumbersA.get(i) : 0) > (i < versionBSize ? versionNumbersB.get(i) : 0)) {
return 1;
} else if ((i < versionASize ? versionNumbersA.get(i) : 0) < (i < versionBSize ? versionNumbersB.get(i) : 0)) {
return -1;
}
}
return 0;
}
This snippet doesn't offer any error checks or handling. Beside that my library also supports suffixes like "1.2-rc" > "1.2-beta".
I am a bit late to the party but I have a great solution for all of you!
1. Use this class:
public class VersionComparator implements Comparator {
public boolean equals(Object o1, Object o2) {
return compare(o1, o2) == 0;
}
public int compare(Object o1, Object o2) {
String version1 = (String) o1;
String version2 = (String) o2;
VersionTokenizer tokenizer1 = new VersionTokenizer(version1);
VersionTokenizer tokenizer2 = new VersionTokenizer(version2);
int number1, number2;
String suffix1, suffix2;
while (tokenizer1.MoveNext()) {
if (!tokenizer2.MoveNext()) {
do {
number1 = tokenizer1.getNumber();
suffix1 = tokenizer1.getSuffix();
if (number1 != 0 || suffix1.length() != 0) {
// Version one is longer than number two, and non-zero
return 1;
}
}
while (tokenizer1.MoveNext());
// Version one is longer than version two, but zero
return 0;
}
number1 = tokenizer1.getNumber();
suffix1 = tokenizer1.getSuffix();
number2 = tokenizer2.getNumber();
suffix2 = tokenizer2.getSuffix();
if (number1 < number2) {
// Number one is less than number two
return -1;
}
if (number1 > number2) {
// Number one is greater than number two
return 1;
}
boolean empty1 = suffix1.length() == 0;
boolean empty2 = suffix2.length() == 0;
if (empty1 && empty2) continue; // No suffixes
if (empty1) return 1; // First suffix is empty (1.2 > 1.2b)
if (empty2) return -1; // Second suffix is empty (1.2a < 1.2)
// Lexical comparison of suffixes
int result = suffix1.compareTo(suffix2);
if (result != 0) return result;
}
if (tokenizer2.MoveNext()) {
do {
number2 = tokenizer2.getNumber();
suffix2 = tokenizer2.getSuffix();
if (number2 != 0 || suffix2.length() != 0) {
// Version one is longer than version two, and non-zero
return -1;
}
}
while (tokenizer2.MoveNext());
// Version two is longer than version one, but zero
return 0;
}
return 0;
}
// VersionTokenizer.java
public static class VersionTokenizer {
private final String _versionString;
private final int _length;
private int _position;
private int _number;
private String _suffix;
private boolean _hasValue;
VersionTokenizer(String versionString) {
if (versionString == null)
throw new IllegalArgumentException("versionString is null");
_versionString = versionString;
_length = versionString.length();
}
public int getNumber() {
return _number;
}
String getSuffix() {
return _suffix;
}
public boolean hasValue() {
return _hasValue;
}
boolean MoveNext() {
_number = 0;
_suffix = "";
_hasValue = false;
// No more characters
if (_position >= _length)
return false;
_hasValue = true;
while (_position < _length) {
char c = _versionString.charAt(_position);
if (c < '0' || c > '9') break;
_number = _number * 10 + (c - '0');
_position++;
}
int suffixStart = _position;
while (_position < _length) {
char c = _versionString.charAt(_position);
if (c == '.') break;
_position++;
}
_suffix = _versionString.substring(suffixStart, _position);
if (_position < _length) _position++;
return true;
}
}
}
2. create this function
private fun isNewVersionAvailable(currentVersion: String, latestVersion: String): Boolean {
val versionComparator = VersionComparator()
val result: Int = versionComparator.compare(currentVersion, latestVersion)
var op = "=="
if (result < 0) op = "<"
if (result > 0) op = ">"
System.out.printf("%s %s %s\n", currentVersion, op, latestVersion)
return if (op == ">" || op == "==") {
false
} else op == "<"
}
3. and just call it by
e.g. isNewVersionAvailable("1.2.8","1.2.9") where 1.2.8 is your current version here and 1.2.9 is the latest version, which returns true!
Why overcomplicate this so much?
Just scale the major, minor, patch version and you have it covered:
fun getAppVersionFromString(version: String): Int { // "2.3.5"
val versions = version.split(".") // [2, 3, 5]
val major = versions[0].toIntOrDefault(0) * 10000 // 20000
val minor = versions[1].toIntOrDefault(0) * 1000 // 3000
val patch = versions[2].toIntOrDefault(0) * 100 // 500
return major + minor + patch // 2350
}
That way when you compare e.g 9.10.10 with 10.0.0 the second one is greater.
Use the following method to compare the versions number:
Convert float to String first.
public static int versionCompare(String str1, String str2) {
String[] vals1 = str1.split("\\.");
String[] vals2 = str2.split("\\.");
int i = 0;
// set index to first non-equal ordinal or length of shortest version string
while (i < vals1.length && i < vals2.length && vals1[i].equals(vals2[i])) {
i++;
}
// compare first non-equal ordinal number
if (i < vals1.length && i < vals2.length) {
int diff = Integer.valueOf(vals1[i]).compareTo(Integer.valueOf(vals2[i]));
return Integer.signum(diff);
}
// the strings are equal or one string is a substring of the other
// e.g. "1.2.3" = "1.2.3" or "1.2.3" < "1.2.3.4"
return Integer.signum(vals1.length - vals2.length);
}
Refer the following SO question : Efficient way to compare version strings in Java
I would like to output a lot of data to my log on Android...but it's truncating the data.
How do I prevent it from truncating my logs?
Logcat truncates data after 4000 characters so you could write it out in chunks:
public static final int LOGCAT_MAX_LINE_LIMIT = 4000;
public static final String TAG = "log_tag";
private void showLog(String message) {
if (message.length() > LOGCAT_MAX_LINE_LIMIT) {
int chunkCount = message.length() / LOGCAT_MAX_LINE_LIMIT;
for (int i = 0; i <= chunkCount; i++) {
int max = LOGCAT_MAX_LINE_LIMIT * (i + 1);
if (max >= message.length()) {
Log.d(TAG, message.substring(LOGCAT_MAX_LINE_LIMIT * i));
} else {
Log.d(TAG, message.substring(LOGCAT_MAX_LINE_LIMIT * i, max));
}
}
} else {
Log.d(TAG, message);
}
}
I need to fill a vector with integers, but I have some troubles, I need to fill it with random numbers, but not two numbers in a row. (ex. not like this: 1,4,4,3,5,9)
I made this code but it does not work well :
# first time loja=1;
but until the game : loja++;
int[] con;
Random Method :
private int nasiqim (int max){
Random nasiqimi = new Random();
int i = 0;
i=nasiqimi.nextInt(max);
return i;
}
Working Code :
int i;
con = new int [loja];
for (i=0; i<loja; i++)
{
con[i] = nasiqim(8);
if(i>0){
while(con[i]==con[i-1])
{
con[i] =nasiqim(8);
}
}
i++;
}
The results are like this:
1
1,4
1,4,1
1,4,1,4
1,4,1,4,1
5,3,5,3,5,3
5,3,5,3,5,3,5
And this is not what I need, I need the numbers to really random, not like this,
Will be great if list will be like this something : 1,5,6,7,3,0,2,4,1,0,2,3...
Thank you!!
private int[] con = null;
private final Random nasiqimi = new Random();
/**
* Test run random.
*/
#Test
public void testRunRandom() {
int loja = 10;
con = new int[loja];
for (int i = 0; i < loja; i++) {
int nextRandom = 0;
while (true) {
nextRandom = nasiqim(8);
if (i == 0 || con[i - 1] != nextRandom) {
con[i] = nextRandom;
break;
}
}
}
}
/**
* Gets the random.
*
* #param max the max
* #return the random
*/
private int nasiqim(int max) {
return nasiqimi.nextInt(max);
}
I've created a sample class
import java.util.*;
public class Foo {
static Random r = new Random();
static int[] con;
static int loja = 8;
private static int randomInt(int max) {
return r.nextInt(max);
}
public static void main(String args[]) {
int i;
con = new int[loja];
for (i = 0; i < loja; i++) {
con[i] = randomInt(8);
if (i > 0) {
while (con[i] == con[i - 1]) {
con[i] = randomInt(8);
}
}
}
System.out.println( Arrays.toString(con));
}
}
All variables are static, notice I get rid of the i++; increment at the end of the for loop.
I want to generate random number in two field between range 1-8 and also field sum should be less than 9.
what I've done done till now
for (int i; i <= 6; i++) {
fieldOne = rand.nextInt(9 - 5) + 5;
fieldTwo = rand.nextInt(9 - 5) + 5;
fieldSum = fieldOne + fieldTwo;
System.out.print(fieldSum); // should be < 9 and not repetition
}
but fieldSum become greater then 9 so How it is control this condition?
And Sequence should be random should not repeat 2 or more time.
rand.nextInt(9-5) won't calculate a random number between 5 and 8, it will make the operation 9 minus 5 and then will calculate rand.nextInt(4).
To calculate a random number between 5 and 8 you have to do something like this:
Random r = new Random();
for (int i = 0; i < 10; i++) {
int rand1 = r.nextInt(4) + 5;
int rand2 = r.nextInt(4) + 5;
int result = rand1 + rand2;
Log.v("", "" + result);
}
The problem is that result can't be < than 9 because you are summing two numbers that are => 5 so the lower result you can get is 10.
Edit for a solution with no repetition:
private List<Integer> rdmNumList = new ArrayList<Integer>();
private final int leftLimitRange = 1;
private final int rightLimitRange = 10;
private final int numOfIteration = 10;
public void generateNumList() {
for (int i = leftLimitRange; i <= rightLimitRange; i++) {
this.rdmNumList.add(num);
}
}
public int getRandomNumer() {
Random r = new Random();
int rNum = r.nextInt(rdmNumList.size());
int result = this.rdmNumList.get(rNum);
this.rdmNumList.remove(rNum);
return result;
}
public void test() {
this.generateNumList();
if(this.numOfIteration <= ((this.rightLimitRange - this.leftLimitRange + 1))) {
for (int i = 0; i < this.numOfIteration; i++) {
Log.v("Debug Output", String.valueOf(this.getRandomNumer()));
}
}
}
Note: this is efficient only with small range of number
This code works but it's far from being good. You should find some other solution by yourself. This answer will help you find your way
Maybe try this --> random.nextInt()%9; another way Get random nuber with random.nextInt(9).
Try,
fieldSum=(fieldOne+fieldTwo)%9;
This will def