• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Losowe zawieszanie się komunikacji z komputerem po UART
#1
Witam,
mam taki dziwny problem z komunikacją, czasem arduino (ten model ) działa bez przerwy ponad tydzień a czasem zawiesi się po kilku godzinach.
W momencie zawieszenia dioda TX świeci bez przerwy i na komputerze nie dam rady się już połączyć, pewnie port jest cały czas zajęty.
Arduino mam zasilane przez zasilacz 9v 2A, ponieważ na zasilaniu z USB wieszało się zdecydowanie częściej. Zasilacz jest na tym samym UPSie co komputer więc to zasilanie nie znika. (nie powinno się przełączyć na 5V)
Przewód USB do połączenia z komputerem ma ok 30cm i jest ekranowany.

Założenia projektu - zliczanie impulsów z różnych źródeł. Impulsy są wykrywane przez arduino i od razu przesyłane po uart. Nie wiem czy w jakiś sposób nie zapycham komunikacji, może jednak należało by kolejkować przychodzące dane i wysyłać je w pakiecie raz na kilka sekund, jednak wiązałoby się to z przebudową obu załączonych programów.
Ale z drugiej strony maksymalnie układ działał bez przerwy przez 12 dni, więc sam już nie wiem.

To mój pierwszy projekt na arduino, zwykle działałem na czystych atmegach, może czegoś tutaj nie widzę.

Uproszczony schemat:
Arduino jest podłączone do komputera za pomocą USB i tym samym USB się komunikuje, zasilane jest z zasilacza. Do wejść jest podpiętych 12 przekaźników według schematu. Żadnych innych połączeń nie ma.


[Obrazek: schemat.png]
Kod arduino:

Kod:
bool buttonState = 0;        
bool lastButtonState = 0;
bool buttonState2 = 0;        
bool lastButtonState2 = 0;
bool buttonState3 = 0;        
bool lastButtonState3 = 0;
bool buttonState4 = 0;        
bool lastButtonState4 = 0;
bool buttonState5 = 0;        
bool lastButtonState5 = 0;
bool buttonState6 = 0;        
bool lastButtonState6 = 0;
bool buttonState7 = 0;        
bool lastButtonState7 = 0;
bool buttonState8 = 0;        
bool lastButtonState8 = 0;
bool buttonState9 = 0;        
bool lastButtonState9 = 0;
bool buttonState10 = 0;        
bool lastButtonState10 = 0;
bool buttonState11 = 0;        
bool lastButtonState11 = 0;
bool buttonState12 = 0;        
bool lastButtonState12 = 0;
byte spu = 0;

void setup() {
 Serial.begin(115200);
 pinMode(0, INPUT);
 digitalWrite(0, HIGH);
 pinMode(1, INPUT);
 digitalWrite(1, HIGH);    
 pinMode(2, INPUT);
 digitalWrite(2, HIGH);  
 pinMode(3, INPUT);
 digitalWrite(3, HIGH);
 pinMode(4, INPUT);
 digitalWrite(4, HIGH);
 pinMode(5, INPUT);
 digitalWrite(5, HIGH);
 pinMode(6, INPUT);
 digitalWrite(6, HIGH);
 pinMode(7, INPUT);
 digitalWrite(7, HIGH);
 pinMode(8, INPUT);
 digitalWrite(8, HIGH);
 pinMode(9, INPUT);
 digitalWrite(9, HIGH);
 pinMode(10, INPUT);
 digitalWrite(10, HIGH);
 pinMode(11, INPUT);
 digitalWrite(11, HIGH);
}

void loop() {

 buttonState = digitalRead(0);
 if (lastButtonState == HIGH) {
   if (buttonState == LOW) {
     Serial.print("a");
     Serial.flush();
   }
   delay(40);
 }
 lastButtonState = buttonState;
 //
 buttonState2 = digitalRead(1);
 if (lastButtonState2 == HIGH) {
   if (buttonState2 == LOW) {
     Serial.print("b");
     Serial.flush();
   }
   delay(40);
 }
 lastButtonState2 = buttonState2;
 //
   buttonState3 = digitalRead(2);
 if (lastButtonState3 == HIGH) {
   if (buttonState3 == LOW) {
     Serial.print("c");
     Serial.flush();
   }
   delay(40);
 }
 lastButtonState3 = buttonState3;
 //
   buttonState4 = digitalRead(3);
 if (lastButtonState4 == HIGH) {
   if (buttonState4 == LOW) {
     Serial.print("d");
     Serial.flush();
   }
   delay(40);
 }
 lastButtonState4 = buttonState4;
   //
   buttonState5 = digitalRead(4);
 if (lastButtonState5 == HIGH) {
   if (buttonState5 == LOW) {
     Serial.print("e");
     Serial.flush();
   }
   delay(40);
 }
 lastButtonState5 = buttonState5;
   //
   buttonState6 = digitalRead(5);
 if (lastButtonState6 == HIGH) {
   if (buttonState6 == LOW) {
     Serial.print("f");
     Serial.flush();
   }
   delay(40);
 }
 lastButtonState6 = buttonState6;
   //
   buttonState7 = digitalRead(6);
 if (lastButtonState7 == HIGH) {
   if (buttonState7 == LOW) {
     Serial.print("g");
     Serial.flush();
   }
   delay(40);
 }
 lastButtonState7 = buttonState7;
   //
   buttonState8 = digitalRead(7);
 if (lastButtonState8 == HIGH) {
   if (buttonState8 == LOW) {
     Serial.print("h");
     Serial.flush();
   }
   delay(40);
 }
 lastButtonState8 = buttonState8;
   //
   buttonState9 = digitalRead(8);
 if (lastButtonState9 == HIGH) {
   if (buttonState9 == LOW) {
     Serial.print("i");
     Serial.flush();
   }
   delay(40);
 }
 lastButtonState9 = buttonState9;
   //
   buttonState10 = digitalRead(9);
 if (lastButtonState10 == HIGH) {
   if (buttonState10 == LOW) {
     spu = spu+1;
   }
   delay(40);
 }
 lastButtonState10 = buttonState10;
 if (spu == 3){
   Serial.print("j");
   Serial.flush();
   spu = 0;
 }
   //
   buttonState11 = digitalRead(10);
 if (lastButtonState11 == HIGH) {
   if (buttonState11 == LOW) {
     Serial.print("k");
     Serial.flush();
   }
   delay(40);
 }
 lastButtonState11 = buttonState11;
   //
   buttonState12 = digitalRead(11);
 if (lastButtonState12 == HIGH) {
   if (buttonState12 == LOW) {
     Serial.print("l");
     Serial.flush();
   }
   delay(40);
 }
 lastButtonState12 = buttonState12;
}

Kod klienta w javie:


Kod:
package centralne_zliczanie;

import java.awt.AWTException;
import java.awt.Desktop;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import static java.awt.SystemColor.menu;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.sql.Time;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.DefaultComboBoxModel;
import javax.swing.Timer;
import javax.swing.text.DefaultCaret;
import jssc.SerialPort;
import jssc.SerialPortEvent;
import jssc.SerialPortEventListener;
import jssc.SerialPortException;
import jssc.SerialPortList;
import jssc.SerialPortTimeoutException;

public class NewJFrame extends javax.swing.JFrame {

   public static boolean watchdog;
   public static SerialPort serialPort;
   public static boolean ikona = true;
   public NewJFrame() {
       initComponents();
       jLabel1.setVisible(false);
       
   String[] portNames = SerialPortList.getPortNames();
   jComboBox1.setModel(new DefaultComboBoxModel(portNames));
}

   @SuppressWarnings("unchecked")
   // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
   private void initComponents() {

       jLabel1 = new javax.swing.JLabel();
       jLabel2 = new javax.swing.JLabel();
       jComboBox1 = new javax.swing.JComboBox<>();
       jLabel3 = new javax.swing.JLabel();
       jButton1 = new javax.swing.JButton();
       jLabel4 = new javax.swing.JLabel();
       jLabel5 = new javax.swing.JLabel();
       jLabel6 = new javax.swing.JLabel();
       jScrollPane1 = new javax.swing.JScrollPane();
       jTextArea1 = new javax.swing.JTextArea();

       setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

       jLabel1.setText("Połączono z portem.");

       jLabel2.setText("Status serwera:");

       jComboBox1.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));

       jLabel3.setText("Wybierz poprawny port COM:");

       jButton1.setText("Połącz");
       jButton1.addActionListener(new java.awt.event.ActionListener() {
           public void actionPerformed(java.awt.event.ActionEvent evt) {
               jButton1ActionPerformed(evt);
           }
       });

       jLabel4.setText("Nie pracuje");

       jLabel5.setText("Status odbieranych danych:");

       jLabel6.setText("Brak");

       jTextArea1.setColumns(20);
       jTextArea1.setRows(5);
       jScrollPane1.setViewportView(jTextArea1);

       javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
       getContentPane().setLayout(layout);
       layout.setHorizontalGroup(
           layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
           .addGroup(layout.createSequentialGroup()
               .addContainerGap()
               .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                   .addComponent(jScrollPane1)
                   .addGroup(layout.createSequentialGroup()
                       .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                           .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                               .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                                   .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE)
                                   .addGap(18, 18, 18)
                                   .addComponent(jButton1))
                               .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                               .addGroup(layout.createSequentialGroup()
                                   .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                       .addComponent(jLabel2)
                                       .addComponent(jLabel5))
                                   .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                   .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                       .addComponent(jLabel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                       .addComponent(jLabel6, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
                           .addComponent(jLabel3))
                       .addGap(0, 0, Short.MAX_VALUE)))
               .addContainerGap())
       );
       layout.setVerticalGroup(
           layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
           .addGroup(layout.createSequentialGroup()
               .addGap(6, 6, 6)
               .addComponent(jLabel3)
               .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
               .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                   .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                   .addComponent(jButton1))
               .addGap(18, 18, 18)
               .addComponent(jLabel1)
               .addGap(18, 18, 18)
               .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                   .addComponent(jLabel2)
                   .addComponent(jLabel4))
               .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
               .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                   .addComponent(jLabel6)
                   .addComponent(jLabel5))
               .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
               .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 95, Short.MAX_VALUE)
               .addContainerGap())
       );

       pack();
   }// </editor-fold>                        
public void resetuj(){
       try {
           serialPort = new SerialPort("COM3");
           serialPort.openPort();
           if(serialPort.isOpened()){
               jLabel1.setVisible(true);
               jLabel4.setText("Uruchomiony");
           }
           serialPort.setParams(115200, 8, 1, 0);
           int mask = SerialPort.MASK_RXCHAR;
           serialPort.setEventsMask(mask);
           serialPort.addEventListener(new NewJFrame.SerialPortReader());
       }
       catch (SerialPortException ex) {
           jLabel4.setText("Nie pracuje");
           jLabel1.setVisible(false);
       }
}
   private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                        
   serialPort = new SerialPort(jComboBox1.getSelectedItem().toString());
   try {
           
           serialPort.openPort();
           if(serialPort.isOpened()){
               jLabel1.setVisible(true);
               jLabel4.setText("Uruchomiony");
           }
           serialPort.setParams(115200, 8, 1, 0);
           int mask = SerialPort.MASK_RXCHAR;
           serialPort.setEventsMask(mask);
           serialPort.addEventListener(new NewJFrame.SerialPortReader());
       }
       catch (SerialPortException ex) {
           jLabel4.setText("Nie pracuje");
           jLabel1.setVisible(false);
       }
   }                                        

   /**
    * @param args the command line arguments
    */
   public static void main(String args[]) {
       NewJFrame frame = new NewJFrame();
       java.awt.EventQueue.invokeLater(new Runnable() {
           public void run() {
               new NewJFrame().setVisible(true);
           }
       });

   }
   
       class SerialPortReader implements SerialPortEventListener {
           NewJFrame frame = new NewJFrame();
       public void serialEvent(SerialPortEvent event) {
           if(event.isRXCHAR()){
               
               try {
                 String nr_maszyny;
                   nr_maszyny = serialPort.readString(1, 100);//readString();
                   serialPort.purgePort (1);
                   serialPort.purgePort (2);
                   if (nr_maszyny.compareTo("a")==0) nr_maszyny="1";
                   if (nr_maszyny.compareTo("b")==0) nr_maszyny="2";
                   if (nr_maszyny.compareTo("c")==0) nr_maszyny="3";
                   if (nr_maszyny.compareTo("d")==0) nr_maszyny="4";
                   if (nr_maszyny.compareTo("e")==0) nr_maszyny="5";
                   if (nr_maszyny.compareTo("f")==0) nr_maszyny="6";
                   if (nr_maszyny.compareTo("g")==0) nr_maszyny="7";
                   if (nr_maszyny.compareTo("h")==0) nr_maszyny="8";
                   if (nr_maszyny.compareTo("i")==0) nr_maszyny="9";
                   if (nr_maszyny.compareTo("j")==0) nr_maszyny="10";
                   if (nr_maszyny.compareTo("k")==0) nr_maszyny="11";
                   if (nr_maszyny.compareTo("l")==0) nr_maszyny="12";
                   Writer output;
                   watchdog = true;
                   File directory = new File(String.valueOf("C:\\zliczanie\\"+LocalDate.now()));
                   if(!directory.exists()){
                       directory.mkdir();
                   }
                   jLabel6.setText("Poprawne");
                   if(nr_maszyny.length()<=1){
                   output = new BufferedWriter(new FileWriter("C:\\zliczanie\\"+LocalDate.now()+"\\maszyna"+nr_maszyny.substring(0, 1)+".txt",true));
                   output.append(Time.valueOf(LocalTime.now())+" "+nr_maszyny.substring(0, 1)+System.lineSeparator());
                   jTextArea1.append(Time.valueOf(LocalTime.now())+" "+nr_maszyny.substring(0, 1)+System.lineSeparator());
                   output.close();
                   }
                   if(nr_maszyny.length()>1){
                   output = new BufferedWriter(new FileWriter("C:\\zliczanie\\"+LocalDate.now()+"\\maszyna"+nr_maszyny.substring(0, 2)+".txt",true));
                   output.append(Time.valueOf(LocalTime.now())+" "+nr_maszyny.substring(0, 2)+System.lineSeparator());
                   if (nr_maszyny.compareTo("10")==0){
                   output.append(Time.valueOf(LocalTime.now())+" "+nr_maszyny.substring(0, 2)+System.lineSeparator());
                   output.append(Time.valueOf(LocalTime.now())+" "+nr_maszyny.substring(0, 2)+System.lineSeparator());
                   }
                   jTextArea1.append(Time.valueOf(LocalTime.now())+" "+nr_maszyny.substring(0, 2)+System.lineSeparator());
                   output.close();
                   jTextArea1.setCaretPosition(jTextArea1.getText().length());
                   }
                   
                   
                   
                   }
                   catch (SerialPortException ex) {
                   jTextArea1.append(ex.toString());
               } catch (IOException ex) {
                   Logger.getLogger(NewJFrame.class.getName()).log(Level.SEVERE, null, ex);
                   jTextArea1.append(ex.toString());
               } catch (SerialPortTimeoutException ex) {
                   Logger.getLogger(NewJFrame.class.getName()).log(Level.SEVERE, null, ex);
               }
           }
       }
   }

   // Variables declaration - do not modify                    
   private javax.swing.JButton jButton1;
   private javax.swing.JComboBox<String> jComboBox1;
   private javax.swing.JLabel jLabel1;
   private javax.swing.JLabel jLabel2;
   private javax.swing.JLabel jLabel3;
   private javax.swing.JLabel jLabel4;
   private javax.swing.JLabel jLabel5;
   private javax.swing.JLabel jLabel6;
   private javax.swing.JScrollPane jScrollPane1;
   private javax.swing.JTextArea jTextArea1;
   // End of variables declaration                  
}


Ten program generuje pliki tekstowe na podstawie odebranych danych, do tego jest jeszcze klient, który te dane pobrane z plików wizualizuje, ale raczej on tu problemu nie robi.
 
Odpowiedź
#2
(27-09-2018, 08:42)case25 napisał(a): To mój pierwszy projekt na arduino, zwykle działałem na czystych atmegach
I trzeba było przy czystych AVR zostać. Jak zmienia się platformę to na lepszą (ARM, ostatecznie Xmega) a nie na gorszą.

W programie nie widzę watchdoga. Obsłuż go. Dodaj sobie także sygnalizację, że pętla główna programu pracuje.
USB w Windows (nie pisałeś  jaki masz system) jest jaki jest. Inne urządzenie podłączone do tego samego HUB-a potrafi wywalić wszystko co jest do niego podłączone. Tu najważniejszy jest soft na kompie. Używaj Javy więc praktycznie na nic nie masz wpływu.
Jeśli system ma działać pewnie na USB (śmieszne, USB i pewność działania) to :
1) Od strony klienta sprzętowe USB. Zaniknie SOF symulujesz odłączenie na chwilę wtyczki USB. Inne rozwiązanie, komp co jakiś czas wysyła jakieś dane. Jeśli ich brak, symulujesz odłączenie na chwilę wtyczki USB.
Jeśli nie jesteś w stanie obsłużyć sprzętowego USB, użyj dobrego mostka USB. Całkiem dobrze sprawują się układy FTDI, CH3xx (przynajmniej pod Win) niestety już nie. Na FTDI mam urządzenia pracujące 24/h nawet po kilka lat. Systemem jest Linux :-)
2) Od strony kompa, musisz wykrywać zniknięcie urządzenia i odpowiednio reagować. Jak to zrealizować nie napiszę, bo nie ja pisze na Win czy Linux wiem tylko czego wymagam - w czasie działania programu, wyjmę i włożę wtyczkę USB, program ma odzyskać komunikację. Czy Twój program odzyskuje komunikacje w takiej sytuacji?
Pomagam (nie prowadzę kursów), tylko, gdy w poście załączone są niezbędne materiały (kod, schemat) a pytający zna podstawy.

Na kod z Delay szkoda czasu.
Kod wymaga komentowania.
Kod bez WDT jest niepewny.



 
Odpowiedź
#3
Ten model Arduino ma USB wbudowany w procek i komunikację "UART" obsługuje się go trochę inaczej. Na pewno brakuje Ci w setup begin, while(!Serial) no i poszukaj po co to jest, czy nie warto tego używać gdzieś w kodzie if(!Serial), ewentualnie zareagować. No i na pewno watchdog nie zaszkodzi. Przyczyna może być też po stronie kabli, softu PC, laptopa, windowsa. Trzeba się bawić i po kolei testować. Dla porównania możesz sobie użyć innych płytek ze zwykłym UART/USB, może będzie Ci łatwiej.
Na płytce z tym samym prockiem (tylko płytka MICRO LEONARDO) mam klawiaturę podłączoną i zasilaną tylko przez USB, zasilanie z portu laptopa USB3 do hub USB3 (nie ma zasilacza) i krótkim kablem do MICRO. No z raz w miesiącu przestaje gadać, trzeba odłączyć HUB. Nie wiem czy to wina HUB'a czy tej płytki Leonardo Micro, czy kablowiska na biurku.
 
Odpowiedź
#4
(27-09-2018, 14:51)kaczakat napisał(a): Na płytce z tym samym prockiem (tylko płytka MICRO LEONARDO)  mam klawiaturę  podłączoną i zasilaną tylko przez USB, zasilanie z portu laptopa USB3 do hub USB3 (nie ma zasilacza) i krótkim kablem do MICRO. No z raz w miesiącu przestaje gadać, trzeba odłączyć HUB. Nie wiem czy to wina HUB'a czy tej płytki Leonardo Micro, czy kablowiska na biurku.

Pewnie pseudosystem Win? Tego typu problemy też mam. Na razie, wszystko wskazuje na problem z Win. Producenci sprzętu obchodzą problemy z pseudosystemem na różne sposoby ale, ze zrozumiałych względów,nie chwalą sie, jakto zrobiły.
Na początek, proponuję zastosować się do moich zaleceń. Jak nie pomogę, cóż, to forum, jak pomogłem, to 1% od zysku (nie wierzę w uczciwość **, więc prędzej Lotto coś wygram).


**
Nie dotyczy wszystkich, tylko 99,9% forumowiczów.
Pomagam (nie prowadzę kursów), tylko, gdy w poście załączone są niezbędne materiały (kod, schemat) a pytający zna podstawy.

Na kod z Delay szkoda czasu.
Kod wymaga komentowania.
Kod bez WDT jest niepewny.



 
Odpowiedź
#5
Zamówię na razie jakiś konwerter na ftdi i pominę układ wbudowany w arduino. Zobaczymy co będzie. System to oczywiście windows, niestety nie do zmiany.
Układ ten to na razie prototyp, jak zajdzie potrzeba to będzie trzeba sięgnąć po profesjonalny sterownik, jednak w miarę sprawdza się to rozwiązanie.

Dzięki za odpowiedzi.
 
Odpowiedź
#6
(28-09-2018, 13:46)case25 napisał(a): Zamówię na razie jakiś konwerter na ftdi i pominę układ wbudowany w arduino
Sugeruję FT220,FT201 po SPI/I2C. Szkoda drogocennego USART na USB.
Pomagam (nie prowadzę kursów), tylko, gdy w poście załączone są niezbędne materiały (kod, schemat) a pytający zna podstawy.

Na kod z Delay szkoda czasu.
Kod wymaga komentowania.
Kod bez WDT jest niepewny.



 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości