11/*
2- Twin_CodeLab v2.4.3
2+ Twin_CodeLab v2.5.0
33
44 Bu yazılım Twin CodeLab Web (https://code.twinscience.com/) ya da mobil uygulamaları ile blok kodlama yapabilme imkanı sunan yazılımdır.
55
66 Arduino IDE üzerinden Twin AIoT modülüne gömülen herhangi bir arduino kodundan sonra Twin Codelab ile blok kodlama yapmak isterseniz bu yazılımı yükleniz gereklidir.
7+
8+ !!! COK ONEMLI !!!: Tools sekmesinden USB CDC on Boot seçeneği "Enabled" olarak seçilmelidir. (USB ile kod çalıştırabilmek için gereklidir)
79
810 Temel olarak bu kod Twin Codelab uygulamalarını çalıştıran donanımlar (bilgisayar, tablet, telefon vb) ile Twin AIoT modülü arasında, Bluetooth bağlantısı üzerinden veri alışverişi yapar ve blok kodlarını çalıştırır.
911
1012 https://github.com/twin-science-robotics/hw_twin_aiot_module_arduino_library
1113
12- 24 Eylül 2025
14+ 09 Ekim 2025
1315 Twin Science & Robotics
1416
1517*/
1820#include " BLEManager.h"
1921#include " CommandHandler.h"
2022
23+ SemaphoreHandle_t serialMutex;
24+ SemaphoreHandle_t canSendPacketSemaphore;
25+
2126// Modüle güç verildiğinde beliren Twin Science logo animasyonu
2227uint8_t twinlogo[][8 ]= {
2328 {0x38 , 0x44 , 0xBA , 0x82 , 0xBA , 0x44 , 0x38 , 0x00 }, // Orijinal
@@ -36,37 +41,21 @@ QueueHandle_t patternQueue;
3641portMUX_TYPE ledmatrix_mux = portMUX_INITIALIZER_UNLOCKED;
3742// Modül setup
3843void setupTwin_F () {
39-
40-
41-
4244 pinMode (D6_output_pin, OUTPUT); // D6
43-
4445 pinMode (D9_output_pin, OUTPUT); // D6
45-
4646 pinMode (D10_output_pin, OUTPUT); // D6
4747
4848 pinMode (S1pin, OUTPUT);
4949 pinMode (S2pin, OUTPUT);
5050 pinMode (S3pin, OUTPUT);
5151
5252 pinMode (D_IN_4, INPUT);
53-
54-
5553 pinMode (D_IN_8, INPUT);
56-
57-
5854 pinMode (D_IN_12, INPUT);
59-
60-
6155 pinMode (AN_IN_4, INPUT);
62-
63-
6456 pinMode (AN_IN_8, INPUT);
65-
66-
6757 pinMode (AN_IN_12, INPUT);
6858
69-
7059 pinMode (latchPin, OUTPUT);
7160 pinMode (clockPin, OUTPUT);
7261 pinMode (dataPin, OUTPUT);
@@ -76,16 +65,17 @@ void setupTwin_F() {
7665
7766 FastLED.addLeds <WS2812B,RGB_PIN , RGB>(leds, 1 );
7867 FastLED.setBrightness (64 );
79-
8068}
8169
8270BLEManager bleManager;
8371CommandHandler commandHandler;
8472
85- QueueHandle_t bleQueue ;
73+ QueueHandle_t commandQueue ;
8674QueueHandle_t responseQueue;
8775
88- channel_st bleChannel;
76+ channel_st channel;
77+ volatile bool isUsbConnected = false ;
78+
8979CRGB leds[NUM_LEDS];
9080
9181// Bluetooth ile alınan veriler işlenir
@@ -95,28 +85,121 @@ void processingTask(void *pvParameters) {
9585 const TickType_t xFrequency = pdMS_TO_TICKS (10 );
9686
9787 while (1 ) {
98- if (xQueueReceive (bleQueue , &receivedCmd, pdMS_TO_TICKS (100 )) == pdTRUE) {
99- commandHandler.handleCommand (receivedCmd);
88+ if (xQueueReceive (commandQueue , &receivedCmd, pdMS_TO_TICKS (10 )) == pdTRUE) { // portMAX_DELAY
89+ commandHandler.handleCommand (receivedCmd);
10090 }
10191 vTaskDelayUntil (&xLastWakeTime, xFrequency);
10292 }
10393}
10494
95+ void sendUSB (const Packet& packet) {
96+ if (xSemaphoreTake (canSendPacketSemaphore, (TickType_t)0 ) == pdTRUE) {
97+ if (xSemaphoreTake (serialMutex, portMAX_DELAY) == pdTRUE) {
98+ uint8_t packet_length = packet.data [4 ] + header_length;
99+ Serial.write (packet.data , packet_length);
100+ xSemaphoreGive (serialMutex);
101+ }
102+ }
103+ else {
104+ // Serial.println("Semaphore alınamadı, paket gönderilemedi.");
105+ }
106+ }
107+
105108// Veri işlendikten sonra cevap dönülür (sensör verileri gibi)
106109void responseTask (void *pvParameters) {
107110 Packet packet;
108111 TickType_t xLastWakeTime = xTaskGetTickCount ();
109- const TickType_t xFrequency = pdMS_TO_TICKS (10 );
112+ const TickType_t xFrequency = pdMS_TO_TICKS (5 );
110113
111114 while (1 ) {
112115 vTaskDelayUntil (&xLastWakeTime, xFrequency);
113116
114- if (xQueueReceive (responseQueue, &packet, pdMS_TO_TICKS (10 )) == pdTRUE) {
115- bleManager.sendResponse (packet);
117+ if (xQueueReceive (responseQueue, &packet, pdMS_TO_TICKS (5 )) == pdTRUE) {
118+ if (packet.source == CHAN_BLE)
119+ bleManager.sendResponse (packet);
120+ else if (packet.source == CHAN_USB) sendUSB (packet);
116121 }
117122 }
118123}
119124
125+ bool readPacketFromSerial (Packet& packet) {
126+ // 1. Senkronizasyon baytını bekle
127+ // readBytesUntil gibi bir fonksiyonla ilk senkron baytını arayabiliriz,
128+ // ama basitlik için bayt bayt okuma daha nettir.
129+ while (Serial.available () > 0 && Serial.read () != SYNC_BYTE1){
130+ vTaskDelay (pdMS_TO_TICKS (5 ));
131+ }
132+
133+ // Seri portta yeterli veri yoksa veya ilk bayt bulunamadıysa çık
134+ if (Serial.available () < (header_length - 1 )) {
135+ return false ;
136+ }
137+
138+ // 2. Başlığın geri kalanını oku
139+ uint8_t header[header_length];
140+ header[0 ] = SYNC_BYTE1; // İlkini zaten bulduk
141+ size_t read_count = Serial.readBytes (&header[1 ], header_length - 1 );
142+
143+ if (read_count != (header_length - 1 )) {
144+ // Beklenen başlık uzunluğu okunamadı, hata.
145+ return false ;
146+ }
147+
148+ // 3. Başlığı doğrula
149+ if (header[1 ] != SYNC_BYTE2 || header[2 ] != SYNC_BYTE3) {
150+ // Senkronizasyon baytları yanlış, bu geçerli bir paket değil.
151+ return false ;
152+ }
153+
154+ // 4. Veri uzunluğunu al ve veriyi oku
155+ uint8_t payload_length = header[4 ];
156+
157+ // Başlığı pakete kopyala
158+ memcpy (packet.data , header, header_length);
159+
160+ if (payload_length > 0 ) {
161+ if (Serial.available () < payload_length) {
162+ // Verinin tamamı henüz gelmemiş, bir sonraki döngüde tekrar deneriz.
163+ // Not: Bu basit yaklaşımda yarım paketler atılır. Daha gelişmiş bir yapı
164+ // state machine ile durumu koruyabilir. Ama çoğu durumda bu yeterlidir.
165+ return false ;
166+ }
167+ // Veriyi başlığın hemen arkasına oku
168+ read_count = Serial.readBytes (&packet.data [header_length], payload_length);
169+ if (read_count != payload_length) {
170+ // Veri okunurken bir sorun oldu.
171+ return false ;
172+ }
173+ }
174+
175+ // Paket başarıyla ve tamamen okundu
176+ return true ;
177+ }
178+
179+
180+ void usbTask (void *pvParameters) {
181+ Packet usbPacket;
182+
183+ while (1 ) {
184+
185+ if (Serial.available () >= header_length) {
186+
187+ memset (&usbPacket, 0 , sizeof (Packet));
188+ if (readPacketFromSerial (usbPacket)) {
189+ // Geçerli bir paket okundu, kuyruğa gönder
190+ usbPacket.source = CHAN_USB;
191+ isUsbConnected = true ;
192+ xSemaphoreGive (canSendPacketSemaphore);
193+ if (xQueueSendToBack (commandQueue, &usbPacket, 0 ) != pdTRUE) {
194+ // Kuyruk dolu, hata yönetimi
195+ // Serial.println("usbqueue error");
196+ }
197+ }
198+ }
199+
200+ vTaskDelay (pdMS_TO_TICKS (20 )); // yogun haberlesmede sorun olursa 10ms test edilebilir
201+ }
202+ }
120203// Led matrixi yenileyen fonksiyon
121204void ledMatrixTask (void *pvParameters) {
122205
@@ -177,7 +260,7 @@ void connTask(void *pvParameters) {
177260 while (1 ) {
178261
179262 vTaskDelayUntil (&xLastWakeTime, xFrequency);
180- currentConnectionState = bleManager.isConnected ();
263+ currentConnectionState = bleManager.isConnected ()|| isUsbConnected ;
181264 // Serial.println(currentConnectionState);
182265
183266 if (currentConnectionState != prevConnectionState) {
@@ -200,7 +283,7 @@ void bleblinkTask(void *pvParameters) {
200283
201284 while (1 ) {
202285
203- if (bleManager.isConnected () == false ){
286+ if (! bleManager.isConnected () && !isUsbConnected ){
204287 // Serial.println("led is on");
205288
206289 leds[0 ] = CRGB (0 ,0 ,255 );
@@ -226,7 +309,7 @@ void scrollIDTask(void *pvParameters) {
226309
227310 while (1 ) {
228311
229- if (bleManager.isConnected () == false ){
312+ if (! bleManager.isConnected () && !isUsbConnected ){
230313
231314 scrollID (offset);
232315 offset++;
@@ -298,16 +381,16 @@ void scrollID(int offset){
298381
299382
300383void setup () {
301- // Serial.begin(115200);
302-
303-
384+ Serial.begin (9600 );
304385 // Kuyrukları oluştur
305- bleQueue = xQueueCreate (QUEUE_LENGTH, sizeof (Packet));
386+ commandQueue = xQueueCreate (QUEUE_LENGTH, sizeof (Packet));
306387 responseQueue = xQueueCreate (QUEUE_LENGTH, sizeof (Packet));
307388 patternQueue = xQueueCreate (QUEUE_LENGTH, sizeof (Packet));
308- moduleName = calculateModuleName () ;
389+ serialMutex = xSemaphoreCreateMutex ();
390+ canSendPacketSemaphore = xSemaphoreCreateBinary ();
309391
310- // Setups
392+ moduleName = calculateModuleName () ;
393+ // Setups
311394 bleManager.setup (moduleName);
312395 setupTwin_F ();
313396 commandHandler.initTwin_F ();
@@ -317,11 +400,10 @@ void setup() {
317400 xTaskCreate (responseTask, " ResponseTask" , 4096 , NULL , 3 , NULL );
318401 xTaskCreate (ledMatrixTask, " ledmatrixTask" , 4096 , NULL , 1 , NULL );
319402 LogoAnimate ();
403+ xTaskCreate (usbTask, " USBTask" , 4096 , NULL , 1 , NULL );
320404 xTaskCreate (connTask, " ConnectionTask" , 4096 , NULL , 1 , NULL );
321405 xTaskCreate (bleblinkTask, " bleblinkTask" , 4096 , NULL , 1 , NULL );
322406 xTaskCreate (scrollIDTask, " scrollIDTask" , 4096 , NULL , 1 , NULL );
323-
324-
325407 // Serial.println(moduleName);
326408}
327409
@@ -383,3 +465,4 @@ String calculateModuleName() {
383465 return " Twin " + colorNames[modVal / 36 ] + colorNames[(modVal % 36 ) / 6 ] + colorNames[modVal % 6 ];
384466}
385467
468+
0 commit comments