Added a lot more documentation for SavvyCAN.
It isn't yet integrated into the program but if you're nosy you can look at the files themselves to get information on how to use SavvyCAN.
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
Bisector Window
|
||||
=================
|
||||
|
||||
.
|
||||
|
||||
.. image:: ./images/Bisector.png
|
||||
|
||||
+2
-2
@@ -55,9 +55,9 @@ author = u'Collin Kidder'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '165'
|
||||
version = '181'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '165'
|
||||
release = '181'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Connection Window
|
||||
=============================
|
||||
==============================
|
||||
|
||||
**Connection Management Window**
|
||||
.
|
||||
|
||||
.. image:: ./images/ConnectionWindow.png
|
||||
|
||||
@@ -10,7 +10,7 @@ At this time GVRET compatible devices are: EVTVDue, EVTV CANDue (1.3/2/2.1/2.2),
|
||||
|
||||
|
||||
Connecting To A Dongle
|
||||
=============================
|
||||
==============================
|
||||
|
||||
SavvyCAN is able to connect to GVRET compatible devices to capture new traffic. These devices will present as serial ports on the connected PC.
|
||||
To connect to a dongle select the proper serial port and click "Create New Connection". If a valid device is found on that serial port the first
|
||||
@@ -27,7 +27,7 @@ for details on configuring such devices.
|
||||
|
||||
|
||||
Debugging Connection Problems
|
||||
=============================
|
||||
==============================
|
||||
GVRET devices present as serial ports and have significant configuration options. However, the ability to configure so many things and the ability to compile the firmware yourself both come as a
|
||||
double edged sword. They present many opportunities for things to go wrong. Because of this there is a debugging console present on the connection window. Click a bus in the table then click "Enable Console"
|
||||
to cause it to start logging serial traffic. From this console you can see what is going on. It shows what SavvyCAN is sending and what it is getting back. It has extended status messages that might help to narrow down
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
Custom Sender Window
|
||||
====================
|
||||
=====================
|
||||
|
||||
**SavvyCAN Custom Frame Sender**
|
||||
.
|
||||
|
||||
.. image:: ./images/CustomSender.png
|
||||
|
||||
|
||||
General Overview
|
||||
=================
|
||||
====================
|
||||
|
||||
This window allows you to create custom frames that will be sent out on one of the can buses. The uses are endless.
|
||||
It can be used to generate valid traffic to control connected hardware. It can be used to test out various ideas
|
||||
@@ -16,7 +16,7 @@ modifications.
|
||||
|
||||
|
||||
Layout of the View
|
||||
===================
|
||||
=====================
|
||||
|
||||
This screen is laid out as a data grid.
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
DBC Message Editor
|
||||
===================
|
||||
|
||||
.
|
||||
|
||||
.. image:: ./images/DBCEditor.png
|
||||
|
||||
Working with Nodes
|
||||
===================
|
||||
|
||||
In DBC files a node is a device on the CAN bus. For instance, the engine control unit (ECU) would be a node as would a motor controller, a battery charger, or any other device that is connected to the CAN bus. DBC files let you define nodes that are
|
||||
set as either the sender or receiver of a message. This allows messages to be organized for more easy retrieval. To add
|
||||
a new node click on the empty row beneath the last defined node and type a new name and optionally a comment. The comment is not used by SavvyCAN but can be filled out for your own reference. When a node is selected in the top list you will then see
|
||||
in the bottom a listing of every message it sends.
|
||||
|
||||
Working with Messages
|
||||
=====================
|
||||
|
||||
The bottom list is all of the messages that are sent by the selected node. A message is defined based on its message ID. The message ID is the CAN id used for this message. For normal DBC files this creates a one to one correspondance of ID to a given CAN ID. For J1939 messages special masking is done and so more than one actual CAN id will map to the given message ID but still only one specific J1939 PGN will come through. Once a message ID is entered in for a new message it will attempt to auto populate the Data Len column with the number of data bytes that message has. This is only for your information, it is not used by SavvyCAN. You can give the DBC message a meaningful name. The "Fg" and "Bg" columns can be clicked on to set a color. This will set the foreground and background color to use for this message. These colors will be used in the main frame view on the main screen when you click "Interpret Frames." Clicking on the "Signals" column will bring up the signals editor for that message so that you can edit, add, or remove signals from the message. The "Comments" column is once again not used by SavvyCAN and only for your viewing reference.
|
||||
@@ -0,0 +1,17 @@
|
||||
DBC File Manager
|
||||
=================
|
||||
|
||||
.
|
||||
|
||||
.. image:: ./images/DBCManager.png
|
||||
|
||||
Working with DBC Files
|
||||
=======================
|
||||
|
||||
This screen allows you to load and save DBC files. SavvyCAN supports loading more than one DBC file at a time. It can even use more than one DBC file per bus. But, "Associated Bus" can be used to associate a given DBC file to only one bus. If you don't need to associate to any specific bus then set this value to -1 which means "any bus." The J1939 button causes SavvyCAN to mask out J1939 message IDs to conform to J1939 signalling. You can create a brand new DBC file by clicking "Create new DBC" button. It will be automatically named a unique name for you. You probably don't want that name though. Any time you save a DBC file its name will automatically update in the list. The "Load", "Save", "Remove", "Edit" buttons are all straight forward. You can also edit a DBC file by double clicking it in the list.
|
||||
|
||||
|
||||
DBC File Ordering
|
||||
===================
|
||||
|
||||
The "Move Up" and "Move Down" buttons can be used to change the order of DBC files. Why would you care? DBC files are accessed in the order they are in the list. When a frame is interpreted the system goes through the DBC files in order. It selects the first DBC file that is associated to the bus the message came in on and that imprements the correct message ID. So, if you have multiple DBC files it is possible that the order might matter.
|
||||
@@ -1,6 +1,32 @@
|
||||
File Comparison Window
|
||||
======================
|
||||
========================
|
||||
|
||||
How to compare one file against one or more other files.
|
||||
.
|
||||
|
||||
.. image:: ./images/FileComparator.png
|
||||
:align: left
|
||||
|
||||
|
||||
The Purpose of the File Comparator
|
||||
==================================
|
||||
|
||||
This screen can be used to figure out what is different between a set of files. On one side you have a single file. This is called the "File of interest". On the other side you have any list of files. They're not listed any longer as actual files. The program can load frames from any number of files and dump them all into the same "bucket" of frames. You can thus load up a batch of files and compare them against the one "File of interest." The purpose of this is to figure out what is different. Are there IDs found only on one side? For IDs found on both sides are there bits set only on one side and not the other? This can be used to find stubborn data that you are having trouble locating. One use is to capture a large amount of traffic to use as "background noise" of sorts. Perhaps drive around for a long time or let the vehicle idle for some time but never do the thing you need to find. Then do another capture and do the thing you're missing a few times. Perhaps you're looking for a gear shift signal. You could capture a large batch of frames while idling. Then, in a second capture shift several times. Now, compare the two. Somewhere in the differences should be the gear selection you couldn't find. The list ought to be much more narrow than just "shooting in the dark" so to speak.
|
||||
|
||||
The layout of the differences list
|
||||
==================================
|
||||
|
||||
In the differences list you'll find three main tree nodes:
|
||||
|
||||
1. IDs found only in <file of interest>
|
||||
|
||||
* In sub nodes you'll find every ID found only in the file of interest and not in any of the reference files.
|
||||
|
||||
2. IDs found only in reference frames
|
||||
|
||||
* In theory this should be a fairly small list. Here are any IDs never seen in the file of interest
|
||||
|
||||
3. IDs found in both
|
||||
|
||||
* Here is where the interesting information lies. The sub nodes here are found in both places. A list of all differences will be shown sub nodes of each ID node. Here you can see bits set only in one side or the other. You can also find values only found on one side or the other. These might be candidates for your mystery signal.
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,48 @@
|
||||
Flow View Window
|
||||
================
|
||||
==================
|
||||
|
||||
Go with the flow
|
||||
.
|
||||
|
||||
.. image:: ./images/FlowView.png
|
||||
|
||||
The Purpose of Flow View
|
||||
=========================
|
||||
|
||||
Flow view is meant to show a view of what "happens to" the data for a given ID as time goes on. The flow is a flow of time or messages going by. The goal is to visualize what is going on as time passes. The screen is very busy but everything has the same goal - to show the data bytes across the list of all frames with that ID.
|
||||
|
||||
Selecting an ID to Flow
|
||||
=======================
|
||||
|
||||
Along the left most side of the window is a list of every frame ID captured so far. You can select any of these IDs. Once you select an ID you'll see the number of frames with that ID just to the right of the IDs list (in the bottom of the Playback Control box).
|
||||
|
||||
Viewing the Flow
|
||||
=================
|
||||
|
||||
There are a variety of ways that the data bytes for the current frame are displayed. Toward the middle of the window there are 8 text boxes that show the current value of each data byte. At the right of the window are two visualizations. On the top there is an 8x8 grid that visualizes every possible bit in a CAN message. Bits which are white are currently 0 or off. Bits which are black are 1 or on. Bits that are green are newly on in this frame. They were 0/off in the reference. Bits which are red are newly off in this frame. Those bits were 1/on in the reference.
|
||||
|
||||
Below the 8x8 grid view is a graph based view. The "+" in the center marks the "current" time. You can thus see both into the future and the past (relative to the current frame) in this view. All 8 data bytes are graphed according to their value. You can thus see in the graph what the value is doing as time ticks by.
|
||||
|
||||
Between these three views you should have a very good idea of how the data bytes change over time.
|
||||
|
||||
Controlling the Flow
|
||||
=====================
|
||||
|
||||
The screen has many ways to control the flow. The "Playback Control" box has 6 icons in a 3x2 grid. The upper icons mean (from left to right): Go back one frame, Stop, Go forward one frame. The bottom icons mean: Play backward, pause, Play forward. Playback speed is used to control how quickly the flow happens. You can raise and lower this value even as the flow is playing back and it will change the flow speed in realtime. You can select "Loop Playback" to keep looping over and over.
|
||||
|
||||
|
||||
Additional control options
|
||||
===========================
|
||||
|
||||
Below the "Playback Control" box is a set of three check boxes. "Live Mode" will cause the flow view to keep the current frame at the latest received frame from the capture hardware. This is thus a "real time" option where the flow will happen in real time as frames come in. "Synchronize windows" causes the flowing in this window to update the position in the main window so that the main window is always at the current position in flow playback. "Graph by timestamp" causes the "Time Axis" at the bottom of the graph view to be in seconds or microseconds. Deselecting this will cause that axis to instead be in frame number.
|
||||
|
||||
Reference Values
|
||||
=================
|
||||
|
||||
Previously it was mentioned that bits in the 8x8 grid are colored based on whether they are
|
||||
newly on/off or steady state compared to the reference. What is the reference? Well, look to the left of the 8x8 grid. The reference values here are used for reference with the 8x8 grid. You can set these values to something static and then see how bits compare to that static reference. Or, above the reference values is a checkbox called "Auto Reference" if this is clicked then the last frame is used as a reference for the current one. There are advantages to both options. A static reference can be used to see how things change compared to, say, the very first frame. Auto reference shows how the data changed from frame to frame. Either might yield interesting findings.
|
||||
|
||||
|
||||
Seeking to Specific Values
|
||||
===========================
|
||||
|
||||
Lastly, it is possible to seek to specific values. "Data Seek Values" normally default to -1. But, if a value other than -1 is found in one of these boxes then it will be used as a seek value. Any time the flow is playing back (either forward or backward) it will compare to the seek values. If there is a match then playback will automatically stop. This can be used to quickly play things back until you get to a specific value. One use would be to seek to a known value that precedes an important section you want to analyze in more depth.
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
Frame Details Window
|
||||
====================
|
||||
======================
|
||||
|
||||
Get all the juicy details about your frames
|
||||
.
|
||||
|
||||
.. image:: ./images/FrameInfoWindow.png
|
||||
|
||||
The Purpose of Frame Details Window
|
||||
===================================
|
||||
|
||||
This window is used to get detailed statistics about frames. It provides information about a given frame ID across all frames with that ID. You can get such information as the number of frames, the number of data bytes that frame ID has, the average interval between frames with that ID, and the minimum and maximum interval. Also listed are detailed statistics for each data byte in that frame. Each byte has listed which bits changed, the range of values found, and a histogram both graphically (at the bottom of the window) and textually. The textual representation shows the number of times a specific value occurred. Also listed at the bottom is a histogram of each bit and how many times it was set. The graph is a histogram of all the bits and the number of times each bit was set. This can be used to quickly visually see where data has changed. All information can be saved to a text file for later analysis.
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
Fuzzing Window
|
||||
===============
|
||||
|
||||
.
|
||||
|
||||
.. image:: ./images/FuzzingWindow.png
|
||||
|
||||
The Purpose of Fuzzing
|
||||
======================
|
||||
|
||||
Some people are big fans of fuzzing, some people have no use for it. There usually isn't much in between. So, what is fuzzing and why would you want to do it? Fuzzing is intentionally sending random information to see what happens. It's pretty much the "shotgun" solution - you fire birdshot into the air and see if it hits anything. Does that sound a bit dangerous? It kind of is. So, why do it? It might help you to find frame IDs that control things. It might help you to find a data byte that controls something. Used carefully it can be used to figure out how different values affect things.
|
||||
|
||||
|
||||
Fuzzing is Dangerous
|
||||
====================
|
||||
You have now been warned. Sending random garbage over the CAN bus to see what happens could mess something up. It just might put your vehicle into gear and cause you to drive over a box full of kittens. Be careful! Never fuzz a car unless you're right there and you can stop it. Even better, don't do it unless your car is up on a hoist or something and can't drive over anyone. Even still, there is a small chance you could cause an adverse effect to your car.
|
||||
|
||||
Controlling the Fuzzy Beast
|
||||
===========================
|
||||
|
||||
So, you want to give it a try? Let's do it! First of all, you can set the delay between frames and the burst rate. The burst rate can cause the program to send one than one frame each interval. This is useful as a CAN bus could potentially support 2000 to 8000 frames per second. Then you can set the number of bytes to send. Ordinarily this would be the full 8 but you can experiment with smaller frames. You can set to send on a specific bus. That's all the simple settings. It gets a bit more complicated now.
|
||||
|
||||
The "ID Scanning" box has two radio buttons:
|
||||
|
||||
1. Sequential will go from "Start ID" to "End ID" then reset back to Start over and over.
|
||||
2. Random will pick IDs at random in the range between Start and End
|
||||
|
||||
But, perhaps you don't want to fuzz IDs like that? The next box is "ID Selection" and the choices are:
|
||||
|
||||
1. Range of IDs - this uses the aforementioned Start and End IDs
|
||||
2. Filter list - This causes it to pick frame IDs from the list below either sequentially or randomly according to the radio boxes under "ID Scanning"
|
||||
|
||||
The last box is "Bit Scanning"
|
||||
|
||||
1. Sequential causes it to scan bits in logically sequential order. That is, the first available fuzzing bit is set then the just the second, then the first two, etc. This causes all of the fuzzed bits to sequentially set in order.
|
||||
2. Sweep causes the system to set the first one, then unset that one and set the second bit, then unset that, etc. Thus the fuzzed bit sweeps and only one fuzzed bit is set at once.
|
||||
3. Random will randomly pick whether each fuzzed bit is set or not.
|
||||
|
||||
In order to fuzz bits you need to set which bits to fuzz and which not to. As listed at the bottom of the window, there is a color code to the 8x8 grid. Clicking cells in the grid will toggle them between their various values. White bits are never set, black bits are always set no matter what, green bits follow the fuzzing pattern you specified in "Bit Scanning"
|
||||
|
||||
Pulling the Trigger
|
||||
===================
|
||||
|
||||
Once you've configured everything click "Start Fuzzing" to give it a shot. You will see the number of frames sent so far listed below the button. You can stop the fuzzing by pushing the button again.
|
||||
@@ -0,0 +1,44 @@
|
||||
Graph Setup
|
||||
============
|
||||
|
||||
.
|
||||
|
||||
.. image:: ./images/GraphSetup.png
|
||||
|
||||
Setting up a Graph
|
||||
==================
|
||||
|
||||
This same screen is used whether you are creating a new graph or editing an existing graph. If you are creating a new graph then you have two options.
|
||||
|
||||
|
||||
Graphing a DBC Signal
|
||||
=====================
|
||||
If you want to graph a signal from a DBC file that you have loaded then pick the Message from the combo box. Picking a message will then allow you to pick a signal within that message. After selecting both the message and the signal then click the "Copy Signal Parameters" button. This will fill out the left hand side with the proper values for you automatically.
|
||||
|
||||
Manual Signal Graphing (Or Editing)
|
||||
===================================
|
||||
|
||||
If you want to manually create a signal or edit an existing signal then you will find the relevant fields on the left hand size of the window.
|
||||
|
||||
"Name" is for your reference and will be shown on the Graphing Window.
|
||||
|
||||
"ID" is the frame ID to use for this graph. You can enter in either decimal or hex. Hex values are preceded by 0x
|
||||
|
||||
"Data Len" is used to specify how many bits are in the signal to graph. You can graph odd bit lengths such as 9, 11, or 15 bits. These are not as uncommon as you might think.
|
||||
|
||||
"Little Endian" switches between little and big endian mode. This will change how the signal grabs bits from the frame.
|
||||
|
||||
Once you've set both Data Len and Little Endian you can set the bits to use. The 8x8 grid above is used for this. Click on the start bit and the rest of the bits will automatically be selected for you based on Data Len and Little Endian.
|
||||
|
||||
"Signed" can be used to select between signed and unsigned mode.
|
||||
|
||||
"Mask" will apply a mask to the value before using it.
|
||||
|
||||
"Bias" allows for setting an offset to the values to bring them to a different resting point
|
||||
|
||||
"Scale" is used as a multiplier to change the scaling of the values
|
||||
|
||||
"Stride" is not often used but will cause only every "x" values to actually be graphed. This can be used to graph a very dense set of data with less points to speed things up.
|
||||
|
||||
"Color" changes the color of the graphed line. It is automatically randomly set for new graphs but if you don't like the random color you can click the color and select a better one.
|
||||
|
||||
@@ -1,4 +1,45 @@
|
||||
Graphing Window
|
||||
===============
|
||||
|
||||
Graphing the data
|
||||
.
|
||||
|
||||
.. image:: ./images/GraphingView.png
|
||||
|
||||
Creating a new Graph
|
||||
=====================
|
||||
Right click in the graph window to bring up a popup menu. The last entry in the first section is "Add new graph". This brings up the Graph Setup Window. From there you can create a new graph.
|
||||
|
||||
Selecting a Graph
|
||||
=================
|
||||
|
||||
You can select a graph either by clicking on it or by clicking its name in the list of graphs up that the top right.
|
||||
|
||||
Editing a Graph
|
||||
=================
|
||||
|
||||
You can either double click its name in the list of graphs at the top right or select the graph, right click, and select "Edit Selected Graph"
|
||||
|
||||
Deleting Graphs
|
||||
================
|
||||
|
||||
There are two options. You can select a graph, right click, and select "Remove selected graph" or you can right click and select "Remove All Graphs"
|
||||
|
||||
Moving Around
|
||||
==============
|
||||
|
||||
Left clicking and dragging in the graphing area will allow you to pan around. The mouse wheel (if you have one) will let you zoom in and out. If you select the numbers on either the X or Y axis then you'll be able to pan and zoom on just that axis leaving the other alone. This is useful in order to expand or shrink the time axis or to rescale the vertical axis to better fit the data in view. The "+" key will zoom in, the "-" key zooms out. You can also zoom in and out from the pop up window that appears when you right click. If you've messed up your view and can't figure out how to fix it then right click and select "Reset View" to get a nice view of all the data again.
|
||||
|
||||
Loading and Saving Graphs
|
||||
=========================
|
||||
|
||||
It can be beneficial to create a set of graphs that can be used over and over. You can save the currently setup graphs to a file and then load it later. Right click on the graphing window and use "Save graph defintions to file" and "Load graph definitions from file" to do this. You can also save a picture of the graphing window. PDF, PNG, and JPG are supported. Lastly, you can save a spreadsheet of all the graphed points.
|
||||
|
||||
Real Time Graphing
|
||||
===================
|
||||
|
||||
Sometimes it is useful to graph while data are still being captured. When this is done it is additionally handy if the view follows the new data. In the right click pop up menu you will find "Follow end of graph". It is a checkbox. When it is on the current view will follow the end of the data captured. The "window" you've set up will scroll. That is, the zoom and vertical calibration will stay the same and only the "Time Axis" will scroll such that the end of the capture is always at the right hand side of the graphing window.
|
||||
|
||||
Hidden Tricks
|
||||
==============
|
||||
|
||||
If you double click on a graphed line the main window will scroll and the frame that produced the nearest data point to where you clicked will be selected. Additionally, if you selected "Synchronize Windows" in Flow view then the graphing view will synchronize to Flow view as well.
|
||||
|
||||
+18
-12
@@ -1,27 +1,33 @@
|
||||
|
||||
Welcome to SavvyCAN's documentation!
|
||||
====================================
|
||||
Welcome to SavvyCAN V181 documentation!
|
||||
=========================================
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:maxdepth: 1
|
||||
:titlesonly:
|
||||
:numbered:
|
||||
|
||||
mainscreen
|
||||
connectionwindow
|
||||
preferences
|
||||
flowview
|
||||
dbc_manager
|
||||
dbc_editor
|
||||
signaleditor
|
||||
graphwindow
|
||||
graphsetup
|
||||
flowview
|
||||
bisector
|
||||
sniffer
|
||||
framedetails
|
||||
filecomparison
|
||||
fuzzingwindow
|
||||
isotp_decoder
|
||||
rangestate
|
||||
uds_scanner
|
||||
playbackwindow
|
||||
customsender
|
||||
firmwareuploader
|
||||
|
||||
scriptingwindow
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
ISO-TP Decoder
|
||||
===============
|
||||
|
||||
.. image:: ./images/ISOTPDecoder.png
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
Main / Start Up Screen
|
||||
======================
|
||||
|
||||
**SavvyCAN main screen**
|
||||
|
||||
.. image:: ./images/MainScreen.png
|
||||
|
||||
This screen embodies the core of the program. Here you will find the master list of all frames. Also, here you can navigate to the other aspects
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
Playback Window
|
||||
===============
|
||||
|
||||
Play back that which was once captured
|
||||
.. image:: ./images/Playback.png
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
Preference Window
|
||||
=================
|
||||
|
||||
So, what do you prefer?
|
||||
.. image:: ./images/Preferences.png
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
Range State Window
|
||||
===================
|
||||
|
||||
.. image:: ./images/RangeState.png
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
Scripting Interface
|
||||
====================
|
||||
|
||||
.. image:: ./images/ScriptingWindow.png
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
DBC Signal Editor
|
||||
=================
|
||||
|
||||
.. image:: ./images/SignalEditor.png
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
Sniffer Window
|
||||
=================
|
||||
|
||||
.. image:: ./images/Sniffer.png
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
UDS Scan Window
|
||||
=================
|
||||
|
||||
.. image:: ./images/UDS_Scanner.png
|
||||
|
||||
|
||||
Reference in New Issue
Block a user