<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://softmc.servotronix.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Nigeller</id>
		<title>SoftMC-Wiki - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="http://softmc.servotronix.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Nigeller"/>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/wiki/Special:Contributions/Nigeller"/>
		<updated>2026-05-14T00:33:19Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=AXY:Linux_MIB&amp;diff=133817</id>
		<title>AXY:Linux MIB</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=AXY:Linux_MIB&amp;diff=133817"/>
				<updated>2022-02-21T08:56:42Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This documentation explains most parts of the Linux MIB. It is intended for the following users:&lt;br /&gt;
&lt;br /&gt;
*softMC developers who are compiling and link C/C++ code &lt;br /&gt;
*QA teams &lt;br /&gt;
*Managers engaged in MIB development &lt;br /&gt;
&lt;br /&gt;
= MIB Software Components =&lt;br /&gt;
&lt;br /&gt;
The software on a common Linux MIB has two main types.&lt;br /&gt;
&lt;br /&gt;
The first type is software controlled by Servotronix, who builds and maintains the source code. The second type is software over which Servotronix has no control, such as third-party binaries.&lt;br /&gt;
&lt;br /&gt;
The first type includes:&lt;br /&gt;
&lt;br /&gt;
*The Linux operating system. This includes all services and utilities along with their shared objects (aka dll) which take part of maintaining the operating system. &lt;br /&gt;
*The Linux Kernel. The core of the operating system. &lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;mc. Manz’s motion control and its bash scripts extensions.&amp;lt;/font&amp;gt; &lt;br /&gt;
*&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;/FFS0 with its mc basic programs.&amp;lt;/font&amp;gt; &lt;br /&gt;
*&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;core dumper. Daemon used to redirect core files.&amp;lt;/font&amp;gt; &lt;br /&gt;
*&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;pkgd. Package manager.&amp;lt;/font&amp;gt; &lt;br /&gt;
*&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;Various in house drivers,such as , sercos 2, ethercat and so on.&amp;lt;/font&amp;gt; &lt;br /&gt;
*&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;In the future, any third party software that is added, such as PNP plugins and 3s.&amp;lt;/font&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;All of the above software is built from source code. Servotronix does not ship any other component without its source code. Binaries passed to MIB through the aico are not considered part of Linux MIB system.&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Accessing the MIB =&lt;br /&gt;
&lt;br /&gt;
The MIB is fully accessable from any machine. Accessing the LinuxMIB can be done in two ways – secure shell and RS232 connection.&lt;br /&gt;
&lt;br /&gt;
== Access LinuxMIB through RS232 ==&lt;br /&gt;
&lt;br /&gt;
It is assumed that you are familiar with RS232 connections.&lt;br /&gt;
&lt;br /&gt;
In Windows you can access the MIB through hyperterminal or putty.&lt;br /&gt;
&lt;br /&gt;
putty.exe can be downloaded from [http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html].&lt;br /&gt;
&amp;lt;pre&amp;gt;'''RS232 Configuration'''&lt;br /&gt;
Speed 115200&lt;br /&gt;
StopBits: 1&lt;br /&gt;
Data: 8&lt;br /&gt;
Parity:Odd ( N)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;Once connected a login session will appear:&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;''manz login:''&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;enter '''mc'''&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;and then:&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;''Password:''&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;Enter '''mc'''&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
== Obtaining LinuxMIB IP ==&lt;br /&gt;
&lt;br /&gt;
If you have aico, use “Select Device” and look for Linux. This should be some LinuxMIB IP.&lt;br /&gt;
&lt;br /&gt;
Alternately, you can access through RS232:&lt;br /&gt;
&amp;lt;pre&amp;gt;~ # '''''ifconfig'''''&lt;br /&gt;
eth0 Link encap:Ethernet HWaddr 00:50:C2:5D:0F:5E&lt;br /&gt;
inet addr:'''10.4.20.83''' Bcast:10.4.20.255 Mask:255.255.255.0&lt;br /&gt;
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1&lt;br /&gt;
RX packets:92287 errors:0 dropped:0 overruns:0 frame:0&lt;br /&gt;
TX packets:4462 errors:0 dropped:0 overruns:0 carrier:0&lt;br /&gt;
collisions:0 txqueuelen:1000&lt;br /&gt;
RX bytes:13389368 (12.7 MiB) TX bytes:431984 (421.8 KiB)&lt;br /&gt;
lo Link encap:Local Loopback&lt;br /&gt;
inet addr:127.0.0.1 Mask:255.0.0.0&lt;br /&gt;
UP LOOPBACK RUNNING MTU:16436 Metric:1&lt;br /&gt;
RX packets:9 errors:0 dropped:0 overruns:0 frame:0&lt;br /&gt;
TX packets:9 errors:0 dropped:0 overruns:0 carrier:0&lt;br /&gt;
collisions:0 txqueuelen:0&lt;br /&gt;
RX bytes:612 (612.0 B) TX bytes:612 (612.0 B)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Access LinuxMIB through Secure Shell ==&lt;br /&gt;
&lt;br /&gt;
To access the MIB from windows without direct connection use secure shell, or in short “ssh”.&lt;br /&gt;
&lt;br /&gt;
If you login through putty, run it. A screen will appear.&lt;br /&gt;
&lt;br /&gt;
[[File:puttyconf.gif|putty]]&lt;br /&gt;
&lt;br /&gt;
Perform the following steps:&lt;br /&gt;
&amp;lt;div align=&amp;quot;left&amp;quot;&amp;gt;1. Choose ssh button&amp;lt;/div&amp;gt; &amp;lt;div align=&amp;quot;left&amp;quot;&amp;gt;2. ssh port is 22 by default&amp;lt;/div&amp;gt; &amp;lt;div align=&amp;quot;left&amp;quot;&amp;gt;3. Fill LinuxMIB ip in both feilds,ie host name and saved sessions.&amp;lt;/div&amp;gt; &amp;lt;div align=&amp;quot;left&amp;quot;&amp;gt;4. save it&amp;lt;/div&amp;gt; &amp;lt;div align=&amp;quot;left&amp;quot;&amp;gt;5. open it&amp;lt;/div&amp;gt; &lt;br /&gt;
A login screen will appear.&lt;br /&gt;
&lt;br /&gt;
[[File:login.gif|putty]]&lt;br /&gt;
&lt;br /&gt;
== Changing the password ==&lt;br /&gt;
&lt;br /&gt;
It is common to change the login password (for developers only):&lt;br /&gt;
&lt;br /&gt;
~ # '''''passwd'''''&lt;br /&gt;
&lt;br /&gt;
Changing password for root&lt;br /&gt;
&lt;br /&gt;
'''''New password:'''''&lt;br /&gt;
&lt;br /&gt;
Enter q&lt;br /&gt;
&lt;br /&gt;
A prompt will appear:&lt;br /&gt;
&lt;br /&gt;
Bad password: too short.&lt;br /&gt;
&lt;br /&gt;
It is ok. “q” is bad password. but you’re likely to login so many times so you better of using this short password.&lt;br /&gt;
&lt;br /&gt;
Then it will ask you to retype the password,&lt;br /&gt;
&lt;br /&gt;
'''''Retype password:'''''&lt;br /&gt;
&lt;br /&gt;
Enter q again. You do not have to enter “q”, but you will learn that people access anyone’s MIB, so they will expect a short packet to be “q”.&lt;br /&gt;
&lt;br /&gt;
= Storage =&lt;br /&gt;
&lt;br /&gt;
This section details the storage of the LinuxMIB. Storage refers to the disks and file systems.&lt;br /&gt;
&lt;br /&gt;
== Block Devices ==&lt;br /&gt;
&lt;br /&gt;
A block device is a device that is accessed with blocks of data. This includes, hard drives, DVD devices, usb flash cards and so on. In the MIB case the block device that holds the file system is called /dev/sda or /dev/hda. It is referred to as /dev/root ( for reasons out this document scope I will not explain why ). Too examin the disk use the fdisk command&amp;amp;nbsp;:&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
fdisk -l&lt;br /&gt;
&lt;br /&gt;
 Disk /dev/sda: 1014 MB, 1014644736 bytes&lt;br /&gt;
 255 heads, 63 sectors/track, 123 cylinders&lt;br /&gt;
 Units = cylinders of 16065 * 512 = 8225280 bytes&lt;br /&gt;
    Device Boot      Start         End      Blocks  Id System&lt;br /&gt;
      /dev/sda1   *           1          57      449850+ 83 Linux&lt;br /&gt;
    Partition 1 does not end on cylinder boundary&lt;br /&gt;
      /dev/sda2              57         116      475000  83 Linux&lt;br /&gt;
    Partition 2 does not end on cylinder boundary&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
/dev/sda1 is / . /dev/sda2 is the backup partition. The backup partion is used /dev/sda1 is totally corrupted.&lt;br /&gt;
&lt;br /&gt;
== File systems ==&lt;br /&gt;
&lt;br /&gt;
LinuxMIB is composed from several independent file systems. To examine the file systems please enter:&lt;br /&gt;
&lt;br /&gt;
~ # ''''df -h''''&lt;br /&gt;
&lt;br /&gt;
                          Filesystem Size     Used    Available  Use%  Mounted on&lt;br /&gt;
&amp;lt;div align=&amp;quot;left&amp;quot;&amp;gt;''1)''&amp;lt;/div&amp;gt; &lt;br /&gt;
                         /dev/root   485.5M   83.8M    377.3M    18%   /  &lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&amp;lt;div align=&amp;quot;left&amp;quot;&amp;gt;''2)''&amp;lt;/div&amp;gt; &lt;br /&gt;
                           none       246.9M   4.0K    246.9M    0% /tmp  &lt;br /&gt;
&amp;lt;div align=&amp;quot;left&amp;quot;&amp;gt;''3)''&amp;lt;/div&amp;gt; &lt;br /&gt;
                            none       246.9M   24.0K   246.8M    0%  /RAM &lt;br /&gt;
                            none       246.9M   44.0K   246.8M    0% /var/log&lt;br /&gt;
                            none       246.9M   24.0K   246.8M    0% /var/run&lt;br /&gt;
&amp;lt;div align=&amp;quot;left&amp;quot;&amp;gt;''4)''&amp;lt;/div&amp;gt; &lt;br /&gt;
                            none       246.9M     0      246.9M   0%   /var/lock&lt;br /&gt;
                            none       246.9M     0      246.9M   0%   /var/tmp&lt;br /&gt;
                            tmpfs      246.9M     4.0K   246.9M    0%  /dev&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
#The main file system is called root file system. The root file system is said to be mounted on the mounting point “/”. Any other file system in Linux is mounted on top of the root file system at some directory. Here the root file system is of size of 485MB, and 83MB of it are used. &lt;br /&gt;
&lt;br /&gt;
#/tmp directory is mounted as tmpfs file system. This is a ram file system. It does not survive boots. &lt;br /&gt;
#This is the RAM file system used by mc. It is also of type tmpfs. &lt;br /&gt;
#/var/log , /var/run, /var/lock, and /var/tmp are tmps file system as well used by different services. &lt;br /&gt;
#/dev/ is a file system that holds all device files. it is regenerated with each boot. &lt;br /&gt;
#There is a nother file system called /dev/pts , it is visible through the mount command, it hold terminals information. &lt;br /&gt;
&lt;br /&gt;
= Basic commands =&lt;br /&gt;
&lt;br /&gt;
== File and file system ==&lt;br /&gt;
&lt;br /&gt;
=== ls ===&lt;br /&gt;
&lt;br /&gt;
To examine the content the of current directory use ls:&lt;br /&gt;
&lt;br /&gt;
~ # ''ls''&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;To examine the content of another directory use ls &amp;lt;dir&amp;gt;. For example:&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
~ # ''ls /sbin/''&lt;br /&gt;
&lt;br /&gt;
adjtimex halt init modprobe setconsole udevadm&lt;br /&gt;
&lt;br /&gt;
blkid hdparm insmod poweroff sfdisk udevd&lt;br /&gt;
&lt;br /&gt;
dhclient hwclock klogd reboot start-stop-daemon udhcpc&lt;br /&gt;
&lt;br /&gt;
fdisk ifconfig loadkmap rmmod sulogin umount.devkit&lt;br /&gt;
&lt;br /&gt;
fsck ifdown lsmod route syslog-ng watchdog&lt;br /&gt;
&lt;br /&gt;
getty ifup modinfo runlevel threads&lt;br /&gt;
&lt;br /&gt;
~ #&lt;br /&gt;
&lt;br /&gt;
The “ls” commands have additional flags, such as&amp;amp;nbsp;: “ls –al” which provides more information about the files.&lt;br /&gt;
&lt;br /&gt;
=== cat ===&lt;br /&gt;
&lt;br /&gt;
To examine the content of a text file use the cat. For example:&lt;br /&gt;
&lt;br /&gt;
~ # ''cat /etc/busybox.conf''&lt;br /&gt;
&lt;br /&gt;
you can also create new files with cat by redirecting cat’s output to a new file. For example:&lt;br /&gt;
&lt;br /&gt;
~ # ''cat /etc/busybox.conf &amp;gt; /tmp/busybox.conf''&lt;br /&gt;
&lt;br /&gt;
you can concatenate two files in to a single file by using the &amp;gt;&amp;gt; sign.&lt;br /&gt;
&lt;br /&gt;
For example the command&lt;br /&gt;
&lt;br /&gt;
~ # ''cat /etc/inet.conf &amp;gt;&amp;gt; /tmp/busybox.conf''&lt;br /&gt;
&lt;br /&gt;
will concatenate to /tmp/busybox.conf the content of /etc/inet.conf.&lt;br /&gt;
&lt;br /&gt;
=== echo ===&lt;br /&gt;
&lt;br /&gt;
echo is a command that send a string to a file, where a file can be the terminal itself or simply a regular text file or any other file which receives data.&lt;br /&gt;
&lt;br /&gt;
~ # echo hello&lt;br /&gt;
&lt;br /&gt;
Hello&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
=== less ===&lt;br /&gt;
&lt;br /&gt;
less is a textual viewer. It is used to examine text file content in read-only mode. Usage:&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;~# less &amp;lt;file name&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== tail/head ===&lt;br /&gt;
&lt;br /&gt;
The tail comands prints last line of a file. The head command prints the first few lines of a file. tail is very useful a user wishes to examine how file is being updated , mostly logs.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
~ # tail –f /var/syslog&lt;br /&gt;
&lt;br /&gt;
=== fsck – check file system consistency ===&lt;br /&gt;
&lt;br /&gt;
LinuxMIB uses ext3 as its file system, ext3 is a journaling file system which means file system corruption is much less to occur, there are still times where corruptions do happen ( not by abrupt power off but by exploding the file system or deliberately corrupting ).&lt;br /&gt;
&lt;br /&gt;
LinuxMIB executes fsck.ext3 each time it is booted, if you wish to check file system integrity first create the device name:&lt;br /&gt;
&lt;br /&gt;
''mknod /dev/hda1 b 3 1''&lt;br /&gt;
&lt;br /&gt;
This is because /dev/hda1 does not exist on the MIB and neither /dev/root.&lt;br /&gt;
&lt;br /&gt;
Now issue the fsck command as bellow. I use –n flag to do that in read only mode.&lt;br /&gt;
&lt;br /&gt;
''fsck.ext3 –n /dev/hda1''&lt;br /&gt;
&lt;br /&gt;
=== grep ===&lt;br /&gt;
&lt;br /&gt;
grep prints lines matching a pattern. Example:&lt;br /&gt;
&lt;br /&gt;
/etc # ''grep mc /usr/bin/mc.sh''&lt;br /&gt;
&lt;br /&gt;
/usr/bin/mc&lt;br /&gt;
&lt;br /&gt;
The above command prints each line containing the word “mc”.&lt;br /&gt;
&lt;br /&gt;
or check number of mc core files in the /cores/ directory.&lt;br /&gt;
&lt;br /&gt;
''nf=$(ls /cores/mc* | wc -l)''&lt;br /&gt;
&lt;br /&gt;
''echo $nf''&lt;br /&gt;
&lt;br /&gt;
4&lt;br /&gt;
&lt;br /&gt;
=== awk ===&lt;br /&gt;
&lt;br /&gt;
awk is a parsing language. The awk command scans an input file searching for some text pattern and when finding this pattern awk act according to the action specified.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
~# awk '$2 == 0 { printf $1 &amp;quot; &amp;quot; $2 &amp;quot; &amp;quot; $3 &amp;quot;\n&amp;quot;}' /proc/interrupts&lt;br /&gt;
&lt;br /&gt;
NMI: 0 Non-maskable&lt;br /&gt;
&lt;br /&gt;
LOC: 0 Local&lt;br /&gt;
&lt;br /&gt;
SPU: 0 Spurious&lt;br /&gt;
&lt;br /&gt;
PMI: 0 Performance&lt;br /&gt;
&lt;br /&gt;
IWI: 0 IRQ&lt;br /&gt;
&lt;br /&gt;
TRM: 0 Thermal&lt;br /&gt;
&lt;br /&gt;
THR: 0 Threshold&lt;br /&gt;
&lt;br /&gt;
MCE: 0 Machine&lt;br /&gt;
&lt;br /&gt;
ERR: 0&lt;br /&gt;
&lt;br /&gt;
MIS: 0&lt;br /&gt;
&lt;br /&gt;
This command prints columns 1, 2 and 3 in the /proc/interrupts if the second column equal 0.&lt;br /&gt;
&lt;br /&gt;
=== find ===&lt;br /&gt;
&lt;br /&gt;
find searches for files in directory recursively. For example, if a user wants to find all files named mc in the LinuxMIB:&lt;br /&gt;
&lt;br /&gt;
~ # find / -name mc&lt;br /&gt;
&lt;br /&gt;
/etc/init.d/mc&lt;br /&gt;
&lt;br /&gt;
/usr/bin/mc&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
=== watch ===&lt;br /&gt;
&lt;br /&gt;
The watch command executes a command periodically. For example:&lt;br /&gt;
&lt;br /&gt;
watch –n1 ‘cat /proc/vmstat`&lt;br /&gt;
&lt;br /&gt;
print to screen the file /proc/vmstat .&lt;br /&gt;
&lt;br /&gt;
=== gzip/gunzip ===&lt;br /&gt;
&lt;br /&gt;
The gzip command compresses a file. The gunzip command decompress a file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
gzip /etc/busybox.conf&lt;br /&gt;
&lt;br /&gt;
busybox.conf is compressed and renamed to busybox.conf.gz&lt;br /&gt;
&lt;br /&gt;
to decompress&amp;amp;nbsp;:&lt;br /&gt;
&lt;br /&gt;
gunzip /etc/busybox.cong.gz&lt;br /&gt;
&lt;br /&gt;
a new file /etc/busybox.conf is created.&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
=== zcat ===&lt;br /&gt;
&lt;br /&gt;
zcat is used to print a content of a compressed text file without decompressing it.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
zcat /etc/busybox.conf.gz&lt;br /&gt;
&lt;br /&gt;
This will dump to screen busybox.conf.a&lt;br /&gt;
&lt;br /&gt;
== System ==&lt;br /&gt;
&lt;br /&gt;
=== free ===&lt;br /&gt;
&lt;br /&gt;
free returns the amount of RAM in the machine, the amount of used memory in the machine and the amount of used memory in the machine.&lt;br /&gt;
&lt;br /&gt;
~ # free&lt;br /&gt;
&lt;br /&gt;
total used free shared buffers&lt;br /&gt;
&lt;br /&gt;
Mem: 505560 47912 457648 0 1356&lt;br /&gt;
&lt;br /&gt;
Swap: 0 0 0&lt;br /&gt;
&lt;br /&gt;
Total: 505560 47912 457648&lt;br /&gt;
&lt;br /&gt;
=== lshw ===&lt;br /&gt;
&lt;br /&gt;
Lists the hardware configuration of the machine.&lt;br /&gt;
&lt;br /&gt;
~ # lshw&lt;br /&gt;
&lt;br /&gt;
manz&lt;br /&gt;
&lt;br /&gt;
description: Computer&lt;br /&gt;
&lt;br /&gt;
product: N/A&lt;br /&gt;
&lt;br /&gt;
vendor: N/A&lt;br /&gt;
&lt;br /&gt;
version: N/A&lt;br /&gt;
&lt;br /&gt;
serial: N/A&lt;br /&gt;
&lt;br /&gt;
width: 32 bits&lt;br /&gt;
&lt;br /&gt;
capabilities: smbios-2.5 dmi-2.5&lt;br /&gt;
&lt;br /&gt;
configuration: administrator_password=disabled boot=oem-specific frontpanel_&lt;br /&gt;
&lt;br /&gt;
password=unknown keyboard_password=unknown power-on_password=disabled&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*-core&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
description: Motherboard&lt;br /&gt;
&lt;br /&gt;
product: MODB&lt;br /&gt;
&lt;br /&gt;
vendor: Kontron Embedded Modules&lt;br /&gt;
&lt;br /&gt;
physical id: 0&lt;br /&gt;
&lt;br /&gt;
version: 05.00&lt;br /&gt;
&lt;br /&gt;
serial: YXEBK0229&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*-firmware&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
description: BIOS&lt;br /&gt;
&lt;br /&gt;
vendor: Phoenix Technologies LTD&lt;br /&gt;
&lt;br /&gt;
physical id: 0&lt;br /&gt;
&lt;br /&gt;
version: MODBR131 (06/27/0808)&lt;br /&gt;
&lt;br /&gt;
size: 104KiB&lt;br /&gt;
&lt;br /&gt;
capacity: 960KiB&lt;br /&gt;
&lt;br /&gt;
capabilities: isa pci pcmcia pnp apm upgrade shadowing escd cdboot acp&lt;br /&gt;
&lt;br /&gt;
i usb agp biosbootspecification&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*-cpu&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
description: CPU&lt;br /&gt;
&lt;br /&gt;
product: Intel(R) Celeron(R) M processor 1.50GHz&lt;br /&gt;
&lt;br /&gt;
vendor: Intel Corp.&lt;br /&gt;
&lt;br /&gt;
physical id: 4&lt;br /&gt;
&lt;br /&gt;
bus info: cpu@0&lt;br /&gt;
&lt;br /&gt;
version: 6.13.8&lt;br /&gt;
&lt;br /&gt;
slot: U2E1&lt;br /&gt;
&lt;br /&gt;
size: 1500MHz&lt;br /&gt;
&lt;br /&gt;
capacity: 2048MHz&lt;br /&gt;
&lt;br /&gt;
width: 32 bits&lt;br /&gt;
&lt;br /&gt;
capabilities: fpu fpu_exception wp vme de pse tsc msr pae mce cx8 sep&lt;br /&gt;
&lt;br /&gt;
mtrr pge mca cmov clflush dts acpi mmx fxsr sse sse2 ss tm pbe nx bts&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*-cache:0&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
description: L1 cache&lt;br /&gt;
&lt;br /&gt;
physical id: 5&lt;br /&gt;
&lt;br /&gt;
slot: L1 Cache&lt;br /&gt;
&lt;br /&gt;
size: 64KiB&lt;br /&gt;
&lt;br /&gt;
capacity: 64KiB&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
=== udevadm ===&lt;br /&gt;
&lt;br /&gt;
udev is part of a linux device model. Udevadm is a tool used to query, monitor and control devices. For example, the hardisk “hda”,has a pci address, it belongs to the block device subsystem, and so on. To get this sort of information in one unified view, we do:&lt;br /&gt;
&lt;br /&gt;
~ # udevadm info -a -p /sys/block/hda&lt;br /&gt;
&lt;br /&gt;
Udevadm info starts with the device specified by the devpath and then&lt;br /&gt;
&lt;br /&gt;
walks up the chain of parent devices. It prints for every device&lt;br /&gt;
&lt;br /&gt;
found, all possible attributes in the udev rules key format.&lt;br /&gt;
&lt;br /&gt;
A rule to match, can be composed by the attributes of the device&lt;br /&gt;
&lt;br /&gt;
and the attributes from one single parent device.&lt;br /&gt;
&lt;br /&gt;
looking at device '/block/hda':&lt;br /&gt;
&lt;br /&gt;
KERNEL==&amp;quot;hda&amp;quot;&lt;br /&gt;
&lt;br /&gt;
SUBSYSTEM==&amp;quot;block&amp;quot;&lt;br /&gt;
&lt;br /&gt;
DRIVER==&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
ATTR{range}==&amp;quot;64&amp;quot;&lt;br /&gt;
&lt;br /&gt;
ATTR{ext_range}==&amp;quot;256&amp;quot;&lt;br /&gt;
&lt;br /&gt;
ATTR{removable}==&amp;quot;0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
ATTR{ro}==&amp;quot;0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
ATTR{size}==&amp;quot;1981728&amp;quot;&lt;br /&gt;
&lt;br /&gt;
ATTR{alignment_offset}==&amp;quot;0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
ATTR{discard_alignment}==&amp;quot;0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
ATTR{capability}==&amp;quot;50&amp;quot;&lt;br /&gt;
&lt;br /&gt;
ATTR{stat}==&amp;quot; 342 173 15716 1119 47 25 1&lt;br /&gt;
&lt;br /&gt;
1768 0 2179 2886&amp;quot;&lt;br /&gt;
&lt;br /&gt;
ATTR{inflight}==&amp;quot; 0 0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
ATTR{events}==&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
ATTR{events_async}==&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
ATTR{events_poll_msecs}==&amp;quot;-1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
As one can observe, a disk called had is part of the block subsystem, there is no driver for it as I did not compile external modules, additional information appears such as its size and some statistics.&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
=== Reboot ===&lt;br /&gt;
&lt;br /&gt;
To reboot the MIB use the “reboot” command.&lt;br /&gt;
&lt;br /&gt;
=== Poweroff ===&lt;br /&gt;
&lt;br /&gt;
To turn off the MIB, use the “poweroff” command.&lt;br /&gt;
&lt;br /&gt;
=== hwclock ===&lt;br /&gt;
&lt;br /&gt;
To get or set the time to/from RTC hardware clock , use the “hwclock” command. In cases where RTC is broken, “hwlock” will hang or display bad time.&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
== Process ==&lt;br /&gt;
&lt;br /&gt;
In this section I show some commands related to processes management.&lt;br /&gt;
&lt;br /&gt;
=== Ps ===&lt;br /&gt;
&lt;br /&gt;
Use the “ps” command to list system processes. For example, the “ps aux” outputs:&lt;br /&gt;
&lt;br /&gt;
~ # ps aux&lt;br /&gt;
&lt;br /&gt;
USER PID&amp;amp;nbsp;%CPU&amp;amp;nbsp;%MEM VSZ RSS TTY STAT START TIME COMMAND&lt;br /&gt;
&lt;br /&gt;
root 1 0.0 0.1 2076 516&amp;amp;nbsp;? Ss 08:03 0:01 init&lt;br /&gt;
&lt;br /&gt;
root 2 0.0 0.0 0 0&amp;amp;nbsp;? S 08:03&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:00 [kthreadd]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 3 0.1 0.0 0 0&amp;amp;nbsp;? S 08:03&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:02 [ksoftirqd/0]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 5 0.0 0.0 0 0&amp;amp;nbsp;? S 08:03&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:00 [kworker/u:0]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 6 0.0 0.0 0 0&amp;amp;nbsp;? S 08:03&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:00 [posixcputmr/0]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 7 0.0 0.0 0 0&amp;amp;nbsp;?&lt;br /&gt;
&amp;lt;nowiki&amp;gt;S&amp;lt; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
08:03 &amp;lt;nowiki&amp;gt;0:00 [khelper]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 8 0.0 0.0 0 0&amp;amp;nbsp;? S 08:03&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:00 [kworker/u:1]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 125 0.0 0.0 0 0&amp;amp;nbsp;? S 08:03&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:00 [sync_supers]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 127 0.0 0.0 0 0&amp;amp;nbsp;? S 08:03&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:00 [bdi-default]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 128 0.0 0.0 0 0&amp;amp;nbsp;?&lt;br /&gt;
&amp;lt;nowiki&amp;gt;S&amp;lt; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
08:03 &amp;lt;nowiki&amp;gt;0:00 [kblockd]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 135 0.0 0.0 0 0&amp;amp;nbsp;?&lt;br /&gt;
&amp;lt;nowiki&amp;gt;S&amp;lt; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
08:03 &amp;lt;nowiki&amp;gt;0:00 [ata_sff]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 142 0.0 0.0 0 0&amp;amp;nbsp;? S 08:03&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:00 [khubd]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 248 0.0 0.0 0 0&amp;amp;nbsp;? S 08:03&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:00 [kworker/0:1]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 268 0.0 0.0 0 0&amp;amp;nbsp;? S 08:03&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:00 [kswapd0]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 269 0.0 0.0 0 0&amp;amp;nbsp;? S 08:03&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:00 [fsnotify_mark]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 271 0.0 0.0 0 0&amp;amp;nbsp;?&lt;br /&gt;
&amp;lt;nowiki&amp;gt;S&amp;lt; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
08:03 &amp;lt;nowiki&amp;gt;0:00 [crypto]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 869 0.0 0.0 0 0&amp;amp;nbsp;? S 08:04&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:00 [irq/15-ide0]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 906 0.0 0.0 0 0&amp;amp;nbsp;? S 08:04&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:00 [irq/1-i8042]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 913 0.0 0.0 0 0&amp;amp;nbsp;? S 08:04&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:00 [irq/8-rtc0]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 921 0.0 0.0 0 0&amp;amp;nbsp;? S 08:04&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:00 [kworker/0:2]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 922 0.0 0.0 0 0&amp;amp;nbsp;? S 08:04&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:00 [irq/4-serial]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 923 0.0 0.0 0 0&amp;amp;nbsp;? S 08:04&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:00 [kjournald]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 945 0.0 0.1 1896 648&amp;amp;nbsp;?&lt;br /&gt;
&amp;lt;nowiki&amp;gt;S&amp;lt;s &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
08:04 0:00 /sbin/udevd --d root 999 0.0 0.1 1892 608&amp;amp;nbsp;? &amp;lt;nowiki&amp;gt;S&amp;lt; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
08:04 0:00 /sbin/udevd --d root 1002 0.0 0.1 1892 604&amp;amp;nbsp;? &amp;lt;nowiki&amp;gt;S&amp;lt; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
08:04 0:00 /sbin/udevd --d root 1017 0.0 0.1 2992 716&amp;amp;nbsp;? Ss 08:04 0:00 /sbin/syslog-ng &lt;br /&gt;
root 1025 0.0 0.1 3932 996&amp;amp;nbsp;? Ss 08:04 0:00 /usr/sbin/sshd&lt;br /&gt;
&lt;br /&gt;
root 1045 0.0 0.0 0 0&amp;amp;nbsp;? S 08:04&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:00 [irq/9-eth0]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 1056 0.0 0.0 0 0&amp;amp;nbsp;? S 08:04&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:00 [irq/11-srcsII]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 1075 99.7 0.0 1528 196&amp;amp;nbsp;? Rs 08:04 31:12 /usr/bin/pkgd /&lt;br /&gt;
&lt;br /&gt;
root 1079 0.0 0.1 2080 544 ttyS0 Ss+ 08:04 0:00 /sbin/getty -L&lt;br /&gt;
&lt;br /&gt;
root 1093 0.0 0.3 6536 2004&amp;amp;nbsp;? Ss 08:04 0:00 sshd: root@pts/&lt;br /&gt;
&lt;br /&gt;
root 1097 0.0 0.1 2080 632 pts/0 Ss+ 08:04 0:00 -sh&lt;br /&gt;
&lt;br /&gt;
root 1107 0.0 0.3 6536 1988&amp;amp;nbsp;? Ss 08:05 0:00 sshd: root@pts/&lt;br /&gt;
&lt;br /&gt;
root 1111 0.0 0.1 2080 664 pts/1 Ss 08:05 0:00 -sh&lt;br /&gt;
&lt;br /&gt;
root 1146 0.0 0.0 0 0&amp;amp;nbsp;? S 08:25&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0:00 [flush-3:0]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
root 1177 0.2 0.3 6536 1988&amp;amp;nbsp;? Ss 08:35 0:00 sshd: root@pts/&lt;br /&gt;
&lt;br /&gt;
root 1181 0.0 0.1 2080 608 pts/2 Ss 08:35 0:00 -sh&lt;br /&gt;
&lt;br /&gt;
root 1182 3.2 5.1 42140 26172 pts/2 Sl+ 08:35 0:00 mc&lt;br /&gt;
&lt;br /&gt;
root 1209 0.0 0.1 2228 824 pts/1 R+ 08:35 0:00 ps aux&lt;br /&gt;
&lt;br /&gt;
all processes in the entire operating system along with their memory consumption, state, pid, cpu usage and so on. As one can see the next to last process is mc itself, so where are his threads. For this I created an abbreviation called threads:&lt;br /&gt;
&lt;br /&gt;
~ # threads&lt;br /&gt;
&lt;br /&gt;
Warning: bad ps syntax, perhaps a bogus '-'? See [http://procps.sf.net/faq.html http://procps.sf.net/faq.html]&lt;br /&gt;
&lt;br /&gt;
PID TID CLS RTPRIO NI PRI PSR&amp;amp;nbsp;%CPU STAT WCHAN COMMAND&lt;br /&gt;
&lt;br /&gt;
1 1 TS - 0 19 0 0.0 Ss wait init&lt;br /&gt;
&lt;br /&gt;
2 2 TS - 0 19 0 0.0 S kthreadd kthreadd&lt;br /&gt;
&lt;br /&gt;
3 3 RR 99 - 139 0 0.1 S run_ksoftirqd ksoftirqd/0&lt;br /&gt;
&lt;br /&gt;
5 5 TS - 0 19 0 0.0 S worker_thread kworker/u:0&lt;br /&gt;
&lt;br /&gt;
6 6 RR 16 - 56 0 0.0 S posix_cpu_time posixcputmr/0&lt;br /&gt;
&lt;br /&gt;
7 7 TS - -20 39 0&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0.0 S&amp;lt; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
rescuer_thread khelper 8 8 TS - 0 19 0 0.0 S worker_thread kworker/u:1 &lt;br /&gt;
125 125 TS - 0 19 0 0.0 S bdi_sync_super sync_supers&lt;br /&gt;
&lt;br /&gt;
127 127 TS - 0 19 0 0.0 S bdi_forker_thr bdi-default&lt;br /&gt;
&lt;br /&gt;
128 128 TS - -20 39 0&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0.0 S&amp;lt; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
rescuer_thread kblockd 135 135 TS - -20 39 0 &amp;lt;nowiki&amp;gt;0.0 S&amp;lt; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
rescuer_thread ata_sff 142 142 TS - 0 19 0 0.0 S hub_thread khubd &lt;br /&gt;
248 248 TS - 0 19 0 0.0 S worker_thread kworker/0:1&lt;br /&gt;
&lt;br /&gt;
268 268 TS - 0 19 0 0.0 S kswapd_try_to_ kswapd0&lt;br /&gt;
&lt;br /&gt;
269 269 TS - 0 19 0 0.0 S fsnotify_mark_ fsnotify_mark&lt;br /&gt;
&lt;br /&gt;
271 271 TS - -20 39 0&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0.0 S&amp;lt; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
rescuer_thread crypto 869 869 FF 50 - 90 0 0.0 S irq_thread irq/15-ide0 &lt;br /&gt;
906 906 RR 16 - 56 0 0.0 S irq_thread irq/1-i8042&lt;br /&gt;
&lt;br /&gt;
913 913 RR 16 - 56 0 0.0 S irq_thread irq/8-rtc0&lt;br /&gt;
&lt;br /&gt;
921 921 TS - 0 19 0 0.0 S worker_thread kworker/0:2&lt;br /&gt;
&lt;br /&gt;
922 922 RR 16 - 56 0 0.0 S irq_thread irq/4-serial&lt;br /&gt;
&lt;br /&gt;
923 923 TS - 0 19 0 0.0 S kjournald kjournald&lt;br /&gt;
&lt;br /&gt;
945 945 TS - -4 23 0&lt;br /&gt;
&amp;lt;nowiki&amp;gt;0.0 S&amp;lt;s &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
poll_schedule_ udevd 999 999 TS - -2 21 0 &amp;lt;nowiki&amp;gt;0.0 S&amp;lt; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
poll_schedule_ udevd 1002 1002 TS - -2 21 0 &amp;lt;nowiki&amp;gt;0.0 S&amp;lt; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
poll_schedule_ udevd 1017 1017 TS - 0 19 0 0.0 Ss poll_schedule_ syslog-ng &lt;br /&gt;
1025 1025 TS - 0 19 0 0.0 Ss poll_schedule_ sshd&lt;br /&gt;
&lt;br /&gt;
1045 1045 RR 16 - 56 0 0.0 S irq_thread irq/9-eth0&lt;br /&gt;
&lt;br /&gt;
1056 1056 RR 99 - 139 0 0.0 S irq_thread irq/11-srcsII&lt;br /&gt;
&lt;br /&gt;
1075 1075 TS - 0 19 0 99.5 Rs - pkgd&lt;br /&gt;
&lt;br /&gt;
1079 1079 TS - 0 19 0 0.0 Ss+ n_tty_read getty&lt;br /&gt;
&lt;br /&gt;
1093 1093 TS - 0 19 0 0.0 Ss poll_schedule_ sshd&lt;br /&gt;
&lt;br /&gt;
1097 1097 TS - 0 19 0 0.0 Ss+ poll_schedule_ sh&lt;br /&gt;
&lt;br /&gt;
1146 1146 TS - 0 19 0 0.0 S bdi_writeback_ flush-3:0&lt;br /&gt;
&lt;br /&gt;
1177 1177 TS - 0 19 0 0.0 Ss poll_schedule_ sshd&lt;br /&gt;
&lt;br /&gt;
1181 1181 TS - 0 19 0 0.0 Ss wait sh&lt;br /&gt;
&lt;br /&gt;
1182 1182 TS - 0 19 0 0.0 Sl+ futex_wait_que mc&lt;br /&gt;
&lt;br /&gt;
1182 1184 RR 1 - 41 0 0.0 Sl+ wq_sleep jexec&lt;br /&gt;
&lt;br /&gt;
1182 1186 RR 25 - 65 0 0.0 Sl+ semtimedop tErrHndl&lt;br /&gt;
&lt;br /&gt;
1182 1187 RR 16 - 56 0 0.0 Sl+ semtimedop tLogger&lt;br /&gt;
&lt;br /&gt;
1182 1188 RR 16 - 56 0 0.0 Sl+ inet_csk_wait_ cli&lt;br /&gt;
&lt;br /&gt;
1182 1189 RR 16 - 56 0 0.0 Sl+ inet_csk_wait_ tEthernInp&lt;br /&gt;
&lt;br /&gt;
1182 1190 RR 16 - 56 0 0.0 Sl+ wait_for_packe tEthernOut&lt;br /&gt;
&lt;br /&gt;
1182 1191 RR 16 - 56 0 0.0 Sl+ inet_csk_wait_ tEthernInp2&lt;br /&gt;
&lt;br /&gt;
1182 1192 RR 16 - 56 0 0.0 Sl+ wait_for_packe tEthernOut2&lt;br /&gt;
&lt;br /&gt;
1182 1193 RR 16 - 56 0 0.0 Sl+ inet_csk_wait_ tEthernInp0&lt;br /&gt;
&lt;br /&gt;
1182 1194 RR 16 - 56 0 0.0 Sl+ wait_for_packe tEthernOut0&lt;br /&gt;
&lt;br /&gt;
1182 1195 RR 16 - 56 0 0.0 Sl+ inet_csk_wait_ tEthernInp3&lt;br /&gt;
&lt;br /&gt;
1182 1196 RR 16 - 56 0 0.0 Sl+ wait_for_packe tEthernOut3&lt;br /&gt;
&lt;br /&gt;
1182 1197 RR 16 - 56 0 0.0 Sl+ wait_for_packe RbootPd&lt;br /&gt;
&lt;br /&gt;
1182 1198 RR 16 - 56 0 0.0 Sl+ poll_schedule_ tVirtualInp&lt;br /&gt;
&lt;br /&gt;
1182 1199 RR 26 - 66 0 0.0 Sl+ hrtimer_nanosl tBit&lt;br /&gt;
&lt;br /&gt;
1182 1200 RR 27 - 67 0 0.4 Sl+ semtimedop tSpy&lt;br /&gt;
&lt;br /&gt;
1182 1201 RR 21 - 61 0 0.1 Sl+ semtimedop tScHandler&lt;br /&gt;
&lt;br /&gt;
1182 1202 RR 20 - 60 0 0.0 Sl+ semtimedop tScServer&lt;br /&gt;
&lt;br /&gt;
1182 1203 RR 21 - 61 0 0.3 SNl+ sercosII_read sercosFun&lt;br /&gt;
&lt;br /&gt;
1182 1204 RR 23 - 63 0 0.0 SNl+ semtimedop MotManager&lt;br /&gt;
&lt;br /&gt;
1182 1207 RR 28 - 68 0 0.1 SNl+ semtimedop tRecPeriodic&lt;br /&gt;
&lt;br /&gt;
1182 1208 RR 29 - 69 0 0.0 SNl+ semtimedop tEvent&lt;br /&gt;
&lt;br /&gt;
1210 1210 TS - 0 19 0 0.6 Ss poll_schedule_ sshd&lt;br /&gt;
&lt;br /&gt;
1214 1214 TS - 0 19 0 0.0 Ss wait sh&lt;br /&gt;
&lt;br /&gt;
1215 1215 TS - 0 19 0 0.0 S+ wait sh&lt;br /&gt;
&lt;br /&gt;
1216 1216 TS - 0 19 0 0.0 R+ - ps&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;threads&amp;quot; is actually a shortcut for the following ps command:&lt;br /&gt;
&lt;br /&gt;
''ps -axH -eo pid,tid,class,rtprio,ni,pri,psr,pcpu,stat,wchan:14,comm''&lt;br /&gt;
&lt;br /&gt;
The above command presents the following information for each task in the operating system:&lt;br /&gt;
&lt;br /&gt;
'''pid''' = process id of the parent not-detached task&lt;br /&gt;
&lt;br /&gt;
'''tid''' = process id of the task within parent task – what we refer as thread.&lt;br /&gt;
&lt;br /&gt;
'''class''' = scheduling class. TS = OTHER, RR = round robin, FF = fifo. - = not reported&lt;br /&gt;
&lt;br /&gt;
'''rtprio''' = real time priority, ranging from 99 to 0. When 99 is strongest.&lt;br /&gt;
&lt;br /&gt;
'''ni''' = niceness. Ranging from -19 to 20.&lt;br /&gt;
&lt;br /&gt;
'''pri''' = static priority.&lt;br /&gt;
&lt;br /&gt;
'''psr''' = processor id.&lt;br /&gt;
&lt;br /&gt;
'''pcpu''' = overall cpu usage&lt;br /&gt;
&lt;br /&gt;
'''stat''' = process state. R for runnable or S for sleeping, Z for zombie.&lt;br /&gt;
&lt;br /&gt;
'''wchan''' = kernel function where process is waiting. If process is running a dash is displayed&lt;br /&gt;
&lt;br /&gt;
'''comm''' = name of process&lt;br /&gt;
&lt;br /&gt;
If you wish to sort the list by the processes real time priority, use the following command:&lt;br /&gt;
&lt;br /&gt;
threads | sort –k4&lt;br /&gt;
&lt;br /&gt;
This command sorts the list according by the fourth column.&lt;br /&gt;
&lt;br /&gt;
=== Kill ===&lt;br /&gt;
&lt;br /&gt;
To terminate a running process use the kill command. Kill needs the process id , so many times you can simply type:&lt;br /&gt;
&lt;br /&gt;
kill -9 $(pidof mc)&lt;br /&gt;
&lt;br /&gt;
Which means, kill anyway, the mc by its process id.&lt;br /&gt;
&lt;br /&gt;
=== Top ===&lt;br /&gt;
&lt;br /&gt;
top is an interactive view of displaying system tasks. It refreshes the list every 1 or more second.&lt;br /&gt;
&lt;br /&gt;
~ # top&lt;br /&gt;
&lt;br /&gt;
top - 09:21:51 up 1:17, 4 users, load average: 1.04, 1.03, 1.01&lt;br /&gt;
&lt;br /&gt;
Tasks: 42 total, 2 running, 40 sleeping, 0 stopped, 0 zombie&lt;br /&gt;
&lt;br /&gt;
Cpu(s): 29.6%us, 70.3%sy, 0.1%ni, 0.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st&lt;br /&gt;
&lt;br /&gt;
Mem: 505536k total, 49120k used, 456416k free, 860k buffers&lt;br /&gt;
&lt;br /&gt;
Swap: 0k total, 0k used, 0k free, 12288k cached&lt;br /&gt;
&lt;br /&gt;
PID USER PR NI VIRT RES SHR S&amp;amp;nbsp;%CPU&amp;amp;nbsp;%MEM TIME+ COMMAND&lt;br /&gt;
&lt;br /&gt;
1075 root 20 0 1528 196 148 R 98.9 0.0 77:03.44 pkgd&lt;br /&gt;
&lt;br /&gt;
1056 root RT 0 0 0 0 S 2.0 0.0 0:05.73 irq/11-srcsII&lt;br /&gt;
&lt;br /&gt;
1 root 20 0 2076 520 460 S 0.0 0.1 0:01.17 init&lt;br /&gt;
&lt;br /&gt;
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd&lt;br /&gt;
&lt;br /&gt;
3 root RT 0 0 0 0 S 0.0 0.0 0:07.44 ksoftirqd/0&lt;br /&gt;
&lt;br /&gt;
5 root 20 0 0 0 0 S 0.0 0.0 0:00.01 kworker/u:0&lt;br /&gt;
&lt;br /&gt;
6 root -17 0 0 0 0 S 0.0 0.0 0:00.00 posixcputmr/0&lt;br /&gt;
&lt;br /&gt;
7 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 khelper&lt;br /&gt;
&lt;br /&gt;
8 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kworker/u:1&lt;br /&gt;
&lt;br /&gt;
125 root 20 0 0 0 0 S 0.0 0.0 0:00.00 sync_supers&lt;br /&gt;
&lt;br /&gt;
127 root 20 0 0 0 0 S 0.0 0.0 0:00.00 bdi-default&lt;br /&gt;
&lt;br /&gt;
128 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kblockd&lt;br /&gt;
&lt;br /&gt;
135 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 ata_sff&lt;br /&gt;
&lt;br /&gt;
142 root 20 0 0 0 0 S 0.0 0.0 0:00.00 khubd&lt;br /&gt;
&lt;br /&gt;
248 root 20 0 0 0 0 S 0.0 0.0 0:00.02 kworker/0:1&lt;br /&gt;
&lt;br /&gt;
268 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kswapd0&lt;br /&gt;
&lt;br /&gt;
269 root 20 0 0 0 0 S 0.0 0.0 0:00.00 fsnotify_mark&lt;br /&gt;
&lt;br /&gt;
271 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 crypto&lt;br /&gt;
&lt;br /&gt;
Top displays a nice summary before the list. Memory usage, cpu usage and so on. Important information is found in this line&lt;br /&gt;
&lt;br /&gt;
Cpu(s): 29.6%us, 70.3%sy, 0.1%ni, 0.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
'''us''' is the Cpu usage in user space here is 29.6%&lt;br /&gt;
&lt;br /&gt;
'''sy''' is the cpu usage in kernel space is 70%&lt;br /&gt;
&lt;br /&gt;
'''ni''' is the niceness of last process&lt;br /&gt;
&lt;br /&gt;
'''wa''' is io wait which is the amount of time system is waiting for IO to complete.&lt;br /&gt;
&lt;br /&gt;
'''hi''' is hardware interrupt usage&lt;br /&gt;
&lt;br /&gt;
'''si''' is soft irqs usage&lt;br /&gt;
&lt;br /&gt;
'''st''' is virtualization usage ( always zero in mib)&lt;br /&gt;
&lt;br /&gt;
=== htop ===&lt;br /&gt;
&lt;br /&gt;
htop is like top but more interactive. You can asks for different sorting keys, like sort by memory usage, sort by cpu usage and so on.&lt;br /&gt;
&lt;br /&gt;
[[Image:]]&lt;br /&gt;
&lt;br /&gt;
Type F6 and toy with it.&lt;br /&gt;
&lt;br /&gt;
=== Display process’s maps ===&lt;br /&gt;
&lt;br /&gt;
To watch a process’ segmented allocation use the following commands:&lt;br /&gt;
&lt;br /&gt;
~ # cat /proc/$(pidof mc)/maps&lt;br /&gt;
&lt;br /&gt;
08048000-08429000 r-xp 00000000 03:01 13462 /usr/bin/mc&lt;br /&gt;
&lt;br /&gt;
08429000-08558000 rwxp 003e1000 03:01 13462 /usr/bin/mc&lt;br /&gt;
&lt;br /&gt;
08558000-085ed000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
09afd000-0b060000 rwxp 00000000 00:00 0&lt;br /&gt;
&amp;lt;nowiki&amp;gt;[heap]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
b5a1c000-b5a1d000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a1d000-b5a24000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a24000-b5a25000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a25000-b5a30000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a30000-b5a31000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a31000-b5a3c000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a3c000-b5a3d000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a3d000-b5a48000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a48000-b5a49000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a49000-b5a58000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a58000-b5a59000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a59000-b5a5c000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a5c000-b5a5d000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a5d000-b5a64000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a64000-b5a65000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a65000-b5a6c000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a6c000-b5a6d000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a6d000-b5a74000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a74000-b5a75000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a75000-b5a80000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a81000-b5a82000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5a82000-b5aa5000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5aa5000-b5aa6000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5aa6000-b5ac1000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5ac1000-b5ac2000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5ac2000-b5ac9000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5ac9000-b5aca000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5aca000-b5aed000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5aed000-b5aee000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5aee000-b5af5000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5af5000-b5af6000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5af6000-b5b19000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5b19000-b5b1a000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5b1a000-b5b21000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5b21000-b5b22000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5b22000-b5b45000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5b45000-b5b46000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5b46000-b5b4d000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5b4d000-b5b4e000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5b4e000-b5c18000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5c18000-b5c19000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b5c19000-b6418000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b6418000-b6419000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b6419000-b6420000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b6420000-b6421000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b6421000-b6429000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b6429000-b642a000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b642a000-b642d000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b642d000-b742d000 rwxs fffe9000000 00:12 2311 /dev/sercosII&lt;br /&gt;
&lt;br /&gt;
b742d000-b742e000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b742e000-b7435000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b7435000-b7436000 ---p 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b7436000-b7544000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b7544000-b7679000 r-xp 00000000 03:01 10172 /lib/libc-2.13.so&lt;br /&gt;
&lt;br /&gt;
b7679000-b767a000 ---p 00135000 03:01 10172 /lib/libc-2.13.so&lt;br /&gt;
&lt;br /&gt;
b767a000-b767c000 r-xp 00135000 03:01 10172 /lib/libc-2.13.so&lt;br /&gt;
&lt;br /&gt;
b767c000-b767d000 rwxp 00137000 03:01 10172 /lib/libc-2.13.so&lt;br /&gt;
&lt;br /&gt;
b767d000-b7680000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b7680000-b769b000 r-xp 00000000 03:01 12467 /lib/libgcc_s.so.1&lt;br /&gt;
&lt;br /&gt;
b769b000-b769c000 rwxp 0001a000 03:01 12467 /lib/libgcc_s.so.1&lt;br /&gt;
&lt;br /&gt;
b769c000-b76c1000 r-xp 00000000 03:01 14763 /lib/libm-2.13.so&lt;br /&gt;
&lt;br /&gt;
b76c1000-b76c2000 r-xp 00024000 03:01 14763 /lib/libm-2.13.so&lt;br /&gt;
&lt;br /&gt;
b76c2000-b76c3000 rwxp 00025000 03:01 14763 /lib/libm-2.13.so&lt;br /&gt;
&lt;br /&gt;
b76c3000-b779b000 r-xp 00000000 03:01 9190 /usr/lib/libstdc++.so.6.0.14&lt;br /&gt;
&lt;br /&gt;
b779b000-b779f000 r-xp 000d7000 03:01 9190 /usr/lib/libstdc++.so.6.0.14&lt;br /&gt;
&lt;br /&gt;
b779f000-b77a0000 rwxp 000db000 03:01 9190 /usr/lib/libstdc++.so.6.0.14&lt;br /&gt;
&lt;br /&gt;
b77a0000-b77a8000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b77a8000-b77b0000 r-xp 00000000 03:01 16731 /lib/libcrypt-2.13.so&lt;br /&gt;
&lt;br /&gt;
b77b0000-b77b1000 r-xp 00007000 03:01 16731 /lib/libcrypt-2.13.so&lt;br /&gt;
&lt;br /&gt;
b77b1000-b77b2000 rwxp 00008000 03:01 16731 /lib/libcrypt-2.13.so&lt;br /&gt;
&lt;br /&gt;
b77b2000-b77d9000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b77d9000-b77ed000 r-xp 00000000 03:01 17714 /lib/libpthread-2.13.so&lt;br /&gt;
&lt;br /&gt;
b77ed000-b77ee000 r-xp 00013000 03:01 17714 /lib/libpthread-2.13.so&lt;br /&gt;
&lt;br /&gt;
b77ee000-b77ef000 rwxp 00014000 03:01 17714 /lib/libpthread-2.13.so&lt;br /&gt;
&lt;br /&gt;
b77ef000-b77f1000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b77f1000-b77f7000 r-xp 00000000 03:01 13450 /lib/librt-2.13.so&lt;br /&gt;
&lt;br /&gt;
b77f7000-b77f8000 r-xp 00005000 03:01 13450 /lib/librt-2.13.so&lt;br /&gt;
&lt;br /&gt;
b77f8000-b77f9000 rwxp 00006000 03:01 13450 /lib/librt-2.13.so&lt;br /&gt;
&lt;br /&gt;
b77f9000-b77fb000 r-xp 00000000 03:01 17388 /lib/libdl-2.13.so&lt;br /&gt;
&lt;br /&gt;
b77fb000-b77fc000 r-xp 00001000 03:01 17388 /lib/libdl-2.13.so&lt;br /&gt;
&lt;br /&gt;
b77fc000-b77fd000 rwxp 00002000 03:01 17388 /lib/libdl-2.13.so&lt;br /&gt;
&lt;br /&gt;
b77fd000-b7817000 r-xp 00000000 03:01 16404 /lib/ld-2.13.so&lt;br /&gt;
&lt;br /&gt;
b7817000-b7818000 rwxp 00000000 00:00 0&lt;br /&gt;
&lt;br /&gt;
b7818000-b7819000 r-xp 0001a000 03:01 16404 /lib/ld-2.13.so&lt;br /&gt;
&lt;br /&gt;
b7819000-b781a000 rwxp 0001b000 03:01 16404 /lib/ld-2.13.so&lt;br /&gt;
&lt;br /&gt;
bfd20000-bfd41000 rwxp 00000000 00:00 0&lt;br /&gt;
&amp;lt;nowiki&amp;gt;[stack]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ffffe000-fffff000 r-xp 00000000 00:00 0&lt;br /&gt;
&amp;lt;nowiki&amp;gt;[vdso]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From left to tight:&lt;br /&gt;
&lt;br /&gt;
#The segment ( also known as vma ) memory addresses &lt;br /&gt;
#The segment permission &lt;br /&gt;
#The segment offset into the file &lt;br /&gt;
#The block device major/minor holding the file &lt;br /&gt;
#The size of the segment &lt;br /&gt;
&lt;br /&gt;
=== chrt ===&lt;br /&gt;
&lt;br /&gt;
change real time priority. You can control a processes scheduling class and priority level from the command line.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
Ksoftirq is a kernel daemon that is widely used in the kernel.&lt;br /&gt;
&lt;br /&gt;
~ # threads |grep sof&lt;br /&gt;
&lt;br /&gt;
3 3 RR 99 - 139 0 0.1 S run_ksoftirqd ksoftirqd/0&lt;br /&gt;
&lt;br /&gt;
ksoftirq pid is 3. Its real time priority is 99. So , let say we wish to change its priority to 19.&lt;br /&gt;
&lt;br /&gt;
~ # chrt -r -p 19 3&lt;br /&gt;
&lt;br /&gt;
pid 3's current scheduling policy: SCHED_RR&lt;br /&gt;
&lt;br /&gt;
pid 3's current scheduling priority: 99&lt;br /&gt;
&lt;br /&gt;
pid 3's new scheduling policy: SCHED_RR&lt;br /&gt;
&lt;br /&gt;
pid 3's new scheduling priority: 19&lt;br /&gt;
&lt;br /&gt;
and indeed priority changed.&lt;br /&gt;
&lt;br /&gt;
~ # threads | grep sof&lt;br /&gt;
&lt;br /&gt;
3 3 RR 19 - 59 0 0.1 S run_ksoftirqd ksoftirqd/0&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
== Network ==&lt;br /&gt;
&lt;br /&gt;
=== ssh sshd and scp ===&lt;br /&gt;
&lt;br /&gt;
Secure shell is used to access remote machines. Sshd is service running in the target MIB and ssh is the client. You can login (perform ssh) to a MIB and login from a MIB to any other Linux machine. You can copy files with scp to and from Linux machines.&lt;br /&gt;
&lt;br /&gt;
To login to MIB ip 10.4.20.240 from any Linux machine enter:&lt;br /&gt;
&lt;br /&gt;
~ # ssh root@10.4.20.240&lt;br /&gt;
&lt;br /&gt;
The authenticity of host '10.4.20.240 (10.4.20.240)' can't be established.&lt;br /&gt;
&lt;br /&gt;
RSA key fingerprint is ef:f6:72:7f:64:7a:21:d4:8b:c3:b2:db:cf:a0:0f:99.&lt;br /&gt;
&lt;br /&gt;
Are you sure you want to continue connecting (yes/no)? yes&lt;br /&gt;
&lt;br /&gt;
Warning: Permanently added '10.4.20.240' (RSA) to the list of known hosts.&lt;br /&gt;
&lt;br /&gt;
root@10.4.20.240's password:&lt;br /&gt;
&lt;br /&gt;
the first you will asked is enter yes/no. this happens only in the first time you access a remote machine. Enter “yes” and then you will be asked to enter a password, please do. Once entered, you will be in the MIB running in root privileges.&lt;br /&gt;
&lt;br /&gt;
To copy files from Linux machine to another Linux machine in the command line we use scp command: for example, the command:&lt;br /&gt;
&lt;br /&gt;
scp –r /tmp root@10.4.20.240:/root/&lt;br /&gt;
&lt;br /&gt;
will copy tmp directory to to root directory in target machine. The “-r” means recursive copy, which is how we copy directories.&lt;br /&gt;
&lt;br /&gt;
If you copy files from a windows machine to a linux machine you should use winscp.&lt;br /&gt;
&lt;br /&gt;
[[File:winscp1.png|winscp]]&lt;br /&gt;
&lt;br /&gt;
The first window displays a list machines that were accessed previously. If this is the first time you use winscp this list is empty. To copy files to 10.4.20.240 please click on the New button.&lt;br /&gt;
&lt;br /&gt;
[[File:winscp2.png|winscp]]&lt;br /&gt;
&lt;br /&gt;
Fill the MIB’s ip. The user name “root”, the password, and change the protocol from sftp to scp. Click on “Save” to save the new machine in the list and then click on Login.&lt;br /&gt;
&lt;br /&gt;
[[File:winscp3.png|winscp]]&lt;br /&gt;
&lt;br /&gt;
You will windows saying that the command “group” returned error, disregard it, it is because MIB does not have group command, after that you will have the above screen. Now you can simply drag and drop files.&lt;br /&gt;
&lt;br /&gt;
=== Route ===&lt;br /&gt;
&lt;br /&gt;
To watch the routing tables just type “route” or “netstat –r”. Here is route output in MIB&lt;br /&gt;
&lt;br /&gt;
Ip 10.4.20.240.&lt;br /&gt;
&lt;br /&gt;
Kernel IP routing table&lt;br /&gt;
&lt;br /&gt;
Destination Gateway Genmask Flags Metric Ref Use Iface&lt;br /&gt;
&lt;br /&gt;
10.0.0.0&lt;br /&gt;
&amp;lt;nowiki&amp;gt;* &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
255.0.0.0 U 0 0 0 eth0 As the reader can see, there is not default route, so if we try to access a different network segment will be getting “unreachable network” . We can only access network on the 10.x.x.x. because the netmask is 255.0.0.0. &lt;br /&gt;
The only Ethernet interface a MIB has is eth0.&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
=== tcpdump ===&lt;br /&gt;
&lt;br /&gt;
tcpdump is a packet capture program. To capture packets simply type:&lt;br /&gt;
&lt;br /&gt;
tcpdump&lt;br /&gt;
&lt;br /&gt;
this will fill screen with traffic captures. If you use ssh to access the machine you will see ssh traffic as well. So you probably want to filter out this ssh traffic. To do that enter:&lt;br /&gt;
&lt;br /&gt;
tcpdump ip –i eth0 and not port 22&lt;br /&gt;
&lt;br /&gt;
Which means, capture all traffic on interface eth0, but drop any traffic on directed to port 22.&lt;br /&gt;
&lt;br /&gt;
There are many other ways to capture traffic. Sometimes you need to capture the traffic and want to analize it later with better tools, like wireshark. For this please enter:&lt;br /&gt;
&lt;br /&gt;
tcpdump ip –i eth0 and not port 22 –w foo.cap&lt;br /&gt;
&lt;br /&gt;
This means that the captured data will be passed to a file called foo.cap.&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
=== ethtool ===&lt;br /&gt;
&lt;br /&gt;
ethtool is used to query and control network interfaces.&lt;br /&gt;
&lt;br /&gt;
~ # ethtool eth0&lt;br /&gt;
&lt;br /&gt;
Settings for eth0:&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;Supported ports: [ TP MII ]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Supported link modes: 10baseT/Half 10baseT/Full&lt;br /&gt;
&lt;br /&gt;
100baseT/Half 100baseT/Full&lt;br /&gt;
&lt;br /&gt;
Supports auto-negotiation: Yes&lt;br /&gt;
&lt;br /&gt;
Advertised link modes: 10baseT/Half 10baseT/Full&lt;br /&gt;
&lt;br /&gt;
100baseT/Half 100baseT/Full&lt;br /&gt;
&lt;br /&gt;
Advertised pause frame use: Symmetric&lt;br /&gt;
&lt;br /&gt;
Advertised auto-negotiation: Yes&lt;br /&gt;
&lt;br /&gt;
Link partner advertised link modes: 10baseT/Half 10baseT/Full&lt;br /&gt;
&lt;br /&gt;
100baseT/Half 100baseT/Full&lt;br /&gt;
&lt;br /&gt;
Link partner advertised pause frame use: Symmetric&lt;br /&gt;
&lt;br /&gt;
Link partner advertised auto-negotiation: Yes&lt;br /&gt;
&lt;br /&gt;
Speed: 100Mb/s&lt;br /&gt;
&lt;br /&gt;
Duplex: Full&lt;br /&gt;
&lt;br /&gt;
Port: MII&lt;br /&gt;
&lt;br /&gt;
PHYAD: 1&lt;br /&gt;
&lt;br /&gt;
Transceiver: internal&lt;br /&gt;
&lt;br /&gt;
Auto-negotiation: on&lt;br /&gt;
&lt;br /&gt;
Supports Wake-on: g&lt;br /&gt;
&lt;br /&gt;
Wake-on: g&lt;br /&gt;
&lt;br /&gt;
Current message level: 0x00000007 (7)&lt;br /&gt;
&lt;br /&gt;
Link detected: yes&lt;br /&gt;
&lt;br /&gt;
Common use for it is checking the link type, 10/100/1000 Mbps and if the network is actually up (Last line: Link Detected).&lt;br /&gt;
&lt;br /&gt;
= Boot =&lt;br /&gt;
&lt;br /&gt;
Linux MIB boot is a two-phase boot. Once the computer passed the POST stage (Power On Self Test) it passes the control to the operating system. The first operating system is actually a boot loader. The boot loader is called grub – “grand unified boot loader”. Grub has one main purpose, to boot Linux. At the moment, the MIB hardware prevents us from seeing the grub loads. When grub loads it splashes a menu to screen (it is called splashing). This menu is kept in /boot/grub/menu.lst which is accessible through the LinuxMIB.&lt;br /&gt;
&lt;br /&gt;
~ # cat /boot/grub/menu.lst&lt;br /&gt;
&lt;br /&gt;
serial --unit=0 --speed=115200&lt;br /&gt;
&lt;br /&gt;
terminal --timeout=0 serial console&lt;br /&gt;
&lt;br /&gt;
default 0&lt;br /&gt;
&lt;br /&gt;
timeout 0&lt;br /&gt;
&lt;br /&gt;
color cyan/blue white/blue&lt;br /&gt;
&lt;br /&gt;
title Standalone Boot&lt;br /&gt;
&lt;br /&gt;
root (hd0,0)&lt;br /&gt;
&lt;br /&gt;
kernel /boot/bzImage root=/dev/hda1,/dev/hdc1 console=ttyS0,115200&lt;br /&gt;
&lt;br /&gt;
title Network Boot&lt;br /&gt;
&lt;br /&gt;
ifconfig --server= --gateway= --mask= --address=&lt;br /&gt;
&lt;br /&gt;
root (nd)&lt;br /&gt;
&lt;br /&gt;
kernel (nd)/linux root=/dev/nfs console=ttyS0,115200 ip=:::::eth0: nfsroot=&lt;br /&gt;
&lt;br /&gt;
~ #&lt;br /&gt;
&lt;br /&gt;
The boot loader menu has two entries, the first entry boots Linux from the disk, and the second one boots Linux from the network. The first one is the default one.&lt;br /&gt;
&lt;br /&gt;
Grub boots the kernel by loading the kernel file (bzImage) to the main memory and passing it some parameters. Current parameters are:&lt;br /&gt;
&lt;br /&gt;
root=/dev/hda1,/dev/hdc1 console=ttyS0, 115200&lt;br /&gt;
&lt;br /&gt;
This means that the kernel search for a root file system in a block device called /dev/hda1 and if it fails it tries /dev/hdc1. The “console=” means that the rs232 input and output redirected through a device file called /dev/ttyS0 in 115200 speed. These parameters are kernel parameters and do not relate to grub.&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
= BSP =&lt;br /&gt;
&lt;br /&gt;
The board specific package I used to create the MIB is Pengutronix. Pengutronix is software builds an entire Linux distribution from scratch. Linux MIB software does not contain any binaries with the sources. So, in this section I will describe how to build the MIB bsp and MC in the virtual disk I supply for this.&lt;br /&gt;
&lt;br /&gt;
== Virtual Build Machine ==&lt;br /&gt;
&lt;br /&gt;
The virtual machine I use to virtual box. Please download and install it. The virtual machine is composed from two virtual disks, mib.vdi and buildDisk.vdi. The mib.vdi is 50MB disk, and buildDisk.vdi is 2 GB disk. This is because the build objects consume a lot of storage. Both disks can be found at //domainaxy/IL/MC/linux/buildmachine . Access to virtual machine is done through the terminal or through ssh with user root , no password required.&lt;br /&gt;
&lt;br /&gt;
'''Virtual Box Configuration'''&lt;br /&gt;
&lt;br /&gt;
storage&lt;br /&gt;
&lt;br /&gt;
[[File:vbox1.png|vbox]]&lt;br /&gt;
&lt;br /&gt;
Network&lt;br /&gt;
&lt;br /&gt;
[[File:vbox2.png|vbox]]&lt;br /&gt;
&lt;br /&gt;
share&lt;br /&gt;
&lt;br /&gt;
[[File:vbox3.png|vbox]]&lt;br /&gt;
&lt;br /&gt;
The guest gets static IP 192.168.56.101 . It is accessible only from the host. We decided to use this configuration as it simplifies things. If you wish to have the Linux connect to the network choose network card attached as bridge and choose intel PRO/1000 MT Desktop.&lt;br /&gt;
&lt;br /&gt;
To have the virtual build machine access s shared folder in the host machine, please add a share name called amcs to whatever folder you wish.&lt;br /&gt;
&lt;br /&gt;
The “amcs” share will mount automatically. Any other share has to be mounted manually in the guest:&lt;br /&gt;
&lt;br /&gt;
mount.vboxsf&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;share name&amp;gt; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;&amp;lt;mount point&amp;gt; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Virtual Linux Configuration'''&lt;br /&gt;
&lt;br /&gt;
The virtual disk containing the toolchain is called toolchain.vdi. Once you boot the virtual build machine you need to make sure build disk is mounted. So check is /opt directory contains OSELAS toolchain. Also, please check the you have network access (with ifconfig) .If all well, please check if you can connect with ssh.&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
=== Building MC ===&lt;br /&gt;
&lt;br /&gt;
#Make sure amcs share is mounted and contains all required sources. Make sure the toolchain is mounted on /opt. &lt;br /&gt;
&lt;br /&gt;
~ # df&lt;br /&gt;
&lt;br /&gt;
Filesystem 1K-blocks Used Available Use% Mounted on&lt;br /&gt;
&lt;br /&gt;
udev 191428 112 191316 0% /dev&lt;br /&gt;
&lt;br /&gt;
tmpfs 76572 144 76428 0% /run&lt;br /&gt;
&lt;br /&gt;
/dev/sda1 147415 85218 54697 61% /&lt;br /&gt;
&lt;br /&gt;
none 191428 0 191428 0% /tmp&lt;br /&gt;
&lt;br /&gt;
none 191428 0 191428 0% /var/log&lt;br /&gt;
&lt;br /&gt;
none 191428 16 191412 0% /var/run&lt;br /&gt;
&lt;br /&gt;
none 191428 0 191428 0% /var/lock&lt;br /&gt;
&lt;br /&gt;
none 191428 0 191428 0% /var/tmp&lt;br /&gt;
&lt;br /&gt;
tmpfs 191428 112 191316 0% /dev&lt;br /&gt;
&lt;br /&gt;
''''/dev/sdb 8256952 1784056 6053468 23% /opt''''&lt;br /&gt;
&lt;br /&gt;
none 4217028 1366328 2850700 32% /media&lt;br /&gt;
&lt;br /&gt;
Change directory to mc sources (inside the amcs share) or clone them from the linux. if this is the first time you build these sources please configure the build as follows:&lt;br /&gt;
&lt;br /&gt;
$ sh run_configure_all and now you can build these sources:&lt;br /&gt;
&lt;br /&gt;
$ make –j2&lt;br /&gt;
&lt;br /&gt;
If you wish to configure eclipse ontop of the virtual box please refer to this document: [[Eclipse_Stand_Alone_Linux|Eclipse Stand Alone Linux]]&lt;br /&gt;
&lt;br /&gt;
Once you’re done, you need to copy the binary to the target machine if you have external networking.&lt;br /&gt;
&lt;br /&gt;
scp mc root@10.4.20.240:/usr/bin/mc&lt;br /&gt;
&lt;br /&gt;
else use eclipse terminal to copy.&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
==== Troubleshoot ====&lt;br /&gt;
&lt;br /&gt;
'''run_configure_all'''&lt;br /&gt;
&lt;br /&gt;
If run_configure_all fails with numerous errors, edit in linux, and remove all ^M signs.&lt;br /&gt;
&lt;br /&gt;
'''Out Of memory'''&lt;br /&gt;
&lt;br /&gt;
Incase during the build you see a message “out of memory” please remove the –j from the make and remake or increase the virtual machine RAM.&lt;br /&gt;
&lt;br /&gt;
'''Out of disk space'''&lt;br /&gt;
&lt;br /&gt;
You are probably building on the virtual machine disk. Change to share directory.&lt;br /&gt;
&lt;br /&gt;
== Toolchain ==&lt;br /&gt;
&lt;br /&gt;
The toochain is installed in the /opt/ directory. This requirement is strict and I do not support any other configuration. The toolchain we use is:&lt;br /&gt;
&lt;br /&gt;
Gcc 4.52&lt;br /&gt;
&lt;br /&gt;
Glibc 2.13&lt;br /&gt;
&lt;br /&gt;
Binutils 2.13&lt;br /&gt;
&lt;br /&gt;
Sanitized kernel headers 2.6.36&lt;br /&gt;
&lt;br /&gt;
Your /opt/ directory should contain a directory called:/opt/OSELAS.Toolchain-2011.03.1/.&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
== The BSP ==&lt;br /&gt;
&lt;br /&gt;
To build the entire bsp you need a linux ubunto server. Building the bsp on a virtual box running ubunto is possible but will take a long time.&lt;br /&gt;
&lt;br /&gt;
You can find the toolchain tar ball&lt;br /&gt;
&lt;br /&gt;
//domainaxy/IL/MC/linux/buildmachine/OSELAS.Toolchain-2011.03.1.tar&lt;br /&gt;
&lt;br /&gt;
Copy it and extract it in the ubunto&amp;amp;nbsp;:&lt;br /&gt;
&lt;br /&gt;
$ sudo tar xvf OSELAS.Toolchain-2011.03.1.tar –C /opt/&lt;br /&gt;
&lt;br /&gt;
Now, clone the bsp:&lt;br /&gt;
&lt;br /&gt;
git clone [mailto:git@10.4.20.38:/home/git/bsp.git git@10.4.20.38:/home/git/bsp.git]&lt;br /&gt;
&lt;br /&gt;
to build the bsp master branch&amp;amp;nbsp;:&lt;br /&gt;
&lt;br /&gt;
cd bsp/&lt;br /&gt;
&lt;br /&gt;
ptxdist go&lt;br /&gt;
&lt;br /&gt;
at the end of the process you will have linuximage in platform-i586/images. This is not enough as you need to build to full image , for this run the bellow command:&lt;br /&gt;
&lt;br /&gt;
ptxdist images&lt;br /&gt;
&lt;br /&gt;
the image is hd.img. To burn it to the sdcard please:&lt;br /&gt;
&lt;br /&gt;
sudo dd if=platform-i586/images/hd.img of=/dev/sdX&lt;br /&gt;
&lt;br /&gt;
when /dev/sdX is the sdcard device name. if you don’t the device name, do not bother dd’ing, you will probably destroy the build server.&lt;br /&gt;
&lt;br /&gt;
Once you dd’ed, please sync and eject:&lt;br /&gt;
&lt;br /&gt;
sync&lt;br /&gt;
&lt;br /&gt;
eject /dev/sdX&lt;br /&gt;
&lt;br /&gt;
=== Replicate an image ===&lt;br /&gt;
&lt;br /&gt;
There are times where one wishes to replicate an existing image. To do that he must copy the source image as file to some Linux machine using dd and then burn the source file image to new card. Here are the steps to do that:&lt;br /&gt;
&lt;br /&gt;
#Place in the card reader the source flash card. Linux will notice a new disk was pushed in. &lt;br /&gt;
#dmesg and look for the new disk name, like /dev/sdd or/dev/sdb. &lt;br /&gt;
&lt;br /&gt;
It will appear in the bottom of the dmesg log, for example:&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;[422238.883418] sd 9:0:0:0: [sdd] Assuming drive cache: write through&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;[422238.883423] sd 9:0:0:0: [sdd] Attached SCSI removable disk&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;[422470.346994] EXT3-fs: barriers not enabled&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;[422470.735075] kjournald starting. &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
Commit interval 5 seconds &amp;amp;nbsp; &amp;lt;nowiki&amp;gt;[422470.735121] EXT3-fs (sdd1): warning: maximal mount count reached, running e2fsck is recommended&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;[422470.736077] EXT3-fs (sdd1): using internal journal&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;[422470.736083] EXT3-fs (sdd1): recovery complete&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;[422470.737199] EXT3-fs (sdd1): mounted filesystem with ordered data mode&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The device ( disk ) in my machine is /dev/sdd. It has a single partition called /dev/sdd1.&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
#Now copy the card to a file using dd: for example, if my disk name is /dev/sdb I enter: &lt;br /&gt;
&lt;br /&gt;
$ dd if=/dev/sdb bs=1M of=/tmp/hd.img&lt;br /&gt;
&lt;br /&gt;
$ sync&lt;br /&gt;
&lt;br /&gt;
#Now pull out the source sd card, and place the new card. &lt;br /&gt;
#Push back the target flash card, and then: &lt;br /&gt;
&lt;br /&gt;
$ dd if=/tmp/hd.img of=/dev/sdb&lt;br /&gt;
&lt;br /&gt;
$ sync&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
= How to edit files in MIB =&lt;br /&gt;
&lt;br /&gt;
There are cases where a user needs to edit a text file in the LinuxMIB. LinuxMIB has two editors, nano and vi.&lt;br /&gt;
&lt;br /&gt;
vi is considered more powerfull than nano. Yet, I believe that the regular user should start with nano as it is more intuitive.&lt;br /&gt;
&lt;br /&gt;
= Upgrade Linux MIB =&lt;br /&gt;
&lt;br /&gt;
Linux MIB is shipped with a debian based packaging system. This means that to any update is wrapped with ipkg. Once the package is ready, simply copy the package file to the target to the inbox directory.&lt;br /&gt;
&lt;br /&gt;
scp mc-4.9.0-linux.ipk 10.4.20.240:/inbox/ or by drag-and-drop through windows operating system with winscp.&lt;br /&gt;
&lt;br /&gt;
Packaging is triggered automatically. I wrote a package manager daemon that listens on /inbox directory and if a new file is put there it tries to install it.&lt;br /&gt;
&lt;br /&gt;
You can list the packages with the following command:&lt;br /&gt;
&lt;br /&gt;
dpkg -l&lt;br /&gt;
&lt;br /&gt;
Currently you cannot uninstall a package, you have to remove the files manually.I believe it is a pengutronix bug.&lt;br /&gt;
&lt;br /&gt;
== Control MC Start ==&lt;br /&gt;
&lt;br /&gt;
One of the first things a programmer does when developing is disabling the automatic start of the application he is debugging. In manz case it is mostly the mc.&lt;br /&gt;
&lt;br /&gt;
There are two ways to disable automatic starting:&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
#Each time you boot. &lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;# ~ /etc/init.d/mc stop&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#Edit /etc/init.d/mc script and remark the mc launching as follows: &lt;br /&gt;
&lt;br /&gt;
…&lt;br /&gt;
&lt;br /&gt;
start)&lt;br /&gt;
&lt;br /&gt;
/etc/init.d/run_config&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;# nohup /bin/sh /usr/bin/mc.sh &amp;amp;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add # before the nohup as depicted in the line above.&lt;br /&gt;
&lt;br /&gt;
= Debugging =&lt;br /&gt;
&lt;br /&gt;
Debugging mc can mostly with eclipse. Please refer to eclipse documentation to learn how to do that.&lt;br /&gt;
&lt;br /&gt;
== Logs ==&lt;br /&gt;
&lt;br /&gt;
In addition to the log files in /RAM file system. We added a linux-like logger which can be found at /var/syslog.&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
== Core files ==&lt;br /&gt;
&lt;br /&gt;
A core file is a snapshot of the process memory when it crashed. It is a post mortem debugging method commonly used. All cores files are generated to /cores directory. There will no more than 5 cores. The 6-th core is written on the first core.&lt;br /&gt;
&lt;br /&gt;
To debug a core dump you must compile the same mc with debug info and copy the core file to the ubunto ( virtual build machine is not suitable for that ). Then type:&lt;br /&gt;
&lt;br /&gt;
gdb mc coredump&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
== Memory Detector ==&lt;br /&gt;
&lt;br /&gt;
To debug memory leaks you need valgrind. Valgrind is not installed as is in the bsp, simply take a package and put it in the target. If you do not know how to use valgrind I suggest you refer to valgrind web site. It is beyond the scope of this paper.&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
== MC cli ==&lt;br /&gt;
&lt;br /&gt;
MC Linux is shipped with a telnet server. This telnet server resembles the vxworks terminal.&lt;br /&gt;
&lt;br /&gt;
To login please:&lt;br /&gt;
&lt;br /&gt;
~ # telnet localhost:8000&lt;br /&gt;
&lt;br /&gt;
Entering character mode&lt;br /&gt;
&lt;br /&gt;
Escape character is '^]'.&lt;br /&gt;
&lt;br /&gt;
AMCS shell&lt;br /&gt;
&lt;br /&gt;
User name is root and password qwerty.&lt;br /&gt;
&lt;br /&gt;
Username: root&lt;br /&gt;
&lt;br /&gt;
Password:&lt;br /&gt;
&lt;br /&gt;
The telnet is evolving and the command may differ from one version to another but to get help you can simply type help.&lt;br /&gt;
&lt;br /&gt;
&amp;gt; help&lt;br /&gt;
&lt;br /&gt;
Commands available:&lt;br /&gt;
&lt;br /&gt;
help Show available commands&lt;br /&gt;
&lt;br /&gt;
logout Disconnect&lt;br /&gt;
&lt;br /&gt;
history Show a list of previously run commands&lt;br /&gt;
&lt;br /&gt;
threads print all threads&lt;br /&gt;
&lt;br /&gt;
stack trace print the stack of a given thread&lt;br /&gt;
&lt;br /&gt;
p print a symbol&lt;br /&gt;
&lt;br /&gt;
exit exit the process&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
== Profiling ==&lt;br /&gt;
&lt;br /&gt;
Profiling MC can be done with oprofile. To use oprofile you need to boot a kernel with oprofile support, and replace the drivers. For this you will have to install a package called kernel-oprofile.ipk and boot this kernel.&lt;br /&gt;
&lt;br /&gt;
To use oprofile please:&lt;br /&gt;
&lt;br /&gt;
$ opcontrol –reset&lt;br /&gt;
&lt;br /&gt;
$ opcontrol –deinit&lt;br /&gt;
&lt;br /&gt;
$ opcontrol –init&lt;br /&gt;
&lt;br /&gt;
Now to choose type of event you should make sure your processor support this type of event – if any.&lt;br /&gt;
&lt;br /&gt;
$ opcontrol –list-events&lt;br /&gt;
&lt;br /&gt;
Let say you wish to check memory references.&lt;br /&gt;
&lt;br /&gt;
$ opcontrol –event:DATA_MEM_REFS:30000&lt;br /&gt;
&lt;br /&gt;
The above command sets the event memory references each time the a a hardware counter finish counting to 30000.&lt;br /&gt;
&lt;br /&gt;
$ opcontrol –session-dir=/home/myoprofile&lt;br /&gt;
&lt;br /&gt;
$ opcontrol –sparate=cpu&lt;br /&gt;
&lt;br /&gt;
$ opcontrol –callgraph=10&lt;br /&gt;
&lt;br /&gt;
$ opcontrol –novmlinux&lt;br /&gt;
&lt;br /&gt;
$ opcontrol –start&lt;br /&gt;
&lt;br /&gt;
./prog..&lt;br /&gt;
&lt;br /&gt;
$ opcontrol –stop&lt;br /&gt;
&lt;br /&gt;
Now copy the entire profiling results to your local machine home user.&lt;br /&gt;
&lt;br /&gt;
$ opreport –session-dir=/home/raz/myprofile&lt;br /&gt;
&lt;br /&gt;
CPU_CLK_UNHALT...|LLC_MISSES:466500|&lt;br /&gt;
&lt;br /&gt;
samples|&amp;amp;nbsp;%| samples|&amp;amp;nbsp;%|&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;------------------------------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
943 100.000 1 100.000 prog&lt;br /&gt;
&lt;br /&gt;
CPU_CLK_UNHALT...|LLC_MISSES:466500|&lt;br /&gt;
&lt;br /&gt;
 samples|&amp;amp;nbsp;%| samples|&amp;amp;nbsp;%|&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;------------------------------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 709 75.1856 1 100.000 prog&lt;br /&gt;
&lt;br /&gt;
 234 24.8144 0 0 libc-2.11.1.so&lt;br /&gt;
&lt;br /&gt;
To get annotation per line use, run this from the mc directory. This way opannotate will find the source code.&lt;br /&gt;
&lt;br /&gt;
$ opanotate –s session-dir=/home/raz/myprofile&lt;br /&gt;
&lt;br /&gt;
Please note if you intend to use oprofile please read the tutotial as it is beyond the spec of this paper.&lt;br /&gt;
&lt;br /&gt;
== ftrace ==&lt;br /&gt;
&lt;br /&gt;
I do not want to write what is ftrace in this book, please refer to the ftrace tutorials to do that:&lt;br /&gt;
&lt;br /&gt;
Here are the steps to ftrace.&lt;br /&gt;
&lt;br /&gt;
Boot the same kernel as the one for ftrace.&lt;br /&gt;
&lt;br /&gt;
$ mount –t debugfs /sys/kernel/debug /debug&lt;br /&gt;
&lt;br /&gt;
$ cd /debug/tracing/&lt;br /&gt;
&lt;br /&gt;
$ echo 0 &amp;gt; tracing_on&lt;br /&gt;
&lt;br /&gt;
$ echo function &amp;gt; current_tracer&lt;br /&gt;
&lt;br /&gt;
$ echo 1 &amp;gt; tracing_on&lt;br /&gt;
&lt;br /&gt;
….&lt;br /&gt;
&lt;br /&gt;
$ echo 0 &amp;gt; tracing_on&lt;br /&gt;
&lt;br /&gt;
File “trace” contains the tracing information. It a huge text file:&lt;br /&gt;
&lt;br /&gt;
$ cat trace&lt;br /&gt;
&lt;br /&gt;
A visual view for ftrace output is known as kernelshark.&lt;br /&gt;
&lt;br /&gt;
To use it please issue the bellow command after you are done with the trace.&lt;br /&gt;
&lt;br /&gt;
$ trace-cmd extract&lt;br /&gt;
&lt;br /&gt;
A local file named trace.dat is created . copy it to your ubunto and launch kernelshard.&lt;br /&gt;
&lt;br /&gt;
$ kernelshark trace.dat&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=MC-Basic:axis.BUSNUMBER&amp;diff=133134</id>
		<title>MC-Basic:axis.BUSNUMBER</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=MC-Basic:axis.BUSNUMBER&amp;diff=133134"/>
				<updated>2018-10-22T07:48:24Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|MC-Basic:axis.BUSNUMBER}}&lt;br /&gt;
{{MC-Basic&lt;br /&gt;
|SHORT FORM=&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
?&amp;lt;''axis''&amp;gt;.BusNumber&lt;br /&gt;
|AVAILABILITY=&lt;br /&gt;
&lt;br /&gt;
Since Version 4.15.2&amp;lt;br&amp;gt;&lt;br /&gt;
0 - EtherCAT&amp;lt;br&amp;gt;&lt;br /&gt;
1 - CANopen&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
This property sets the field bus to which the axis is connected&lt;br /&gt;
|TYPE=&lt;br /&gt;
Long&lt;br /&gt;
&lt;br /&gt;
|RANGE=&lt;br /&gt;
(-1) - Default value, after start up or &amp;quot;reset all&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
0 - EtherCAT&amp;lt;br&amp;gt;&lt;br /&gt;
1 - CANopen&lt;br /&gt;
|UNITS=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|DEFAULT=&lt;br /&gt;
&lt;br /&gt;
|SCOPE=&lt;br /&gt;
Configuration, Task or Terminal.&lt;br /&gt;
&lt;br /&gt;
|LIMITATIONS=&lt;br /&gt;
Till version 4.15.2 Read-only&lt;br /&gt;
&lt;br /&gt;
|EXAMPLE=&lt;br /&gt;
?Axis1.BusNumber&lt;br /&gt;
&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=MC-Basic:axis.BUSNUMBER&amp;diff=133133</id>
		<title>MC-Basic:axis.BUSNUMBER</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=MC-Basic:axis.BUSNUMBER&amp;diff=133133"/>
				<updated>2018-10-22T07:48:07Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
{{MC-Basic&lt;br /&gt;
|SHORT FORM=&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
?&amp;lt;''axis''&amp;gt;.BusNumber&lt;br /&gt;
|AVAILABILITY=&lt;br /&gt;
&lt;br /&gt;
Since Version 4.15.2&amp;lt;br&amp;gt;&lt;br /&gt;
0 - EtherCAT&amp;lt;br&amp;gt;&lt;br /&gt;
1 - CANopen&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
This property sets the field bus to which the axis is connected&lt;br /&gt;
|TYPE=&lt;br /&gt;
Long&lt;br /&gt;
&lt;br /&gt;
|RANGE=&lt;br /&gt;
-1 - Default value, after start up or &amp;quot;reset all&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
0 - EtherCAT&amp;lt;br&amp;gt;&lt;br /&gt;
1 - CANopen&lt;br /&gt;
|UNITS=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|DEFAULT=&lt;br /&gt;
&lt;br /&gt;
|SCOPE=&lt;br /&gt;
Configuration, Task or Terminal.&lt;br /&gt;
&lt;br /&gt;
|LIMITATIONS=&lt;br /&gt;
Till version 4.15.2 Read-only&lt;br /&gt;
&lt;br /&gt;
|EXAMPLE=&lt;br /&gt;
?Axis1.BusNumber&lt;br /&gt;
&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=MC-Basic:axis.BUSNUMBER&amp;diff=133132</id>
		<title>MC-Basic:axis.BUSNUMBER</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=MC-Basic:axis.BUSNUMBER&amp;diff=133132"/>
				<updated>2018-10-22T07:47:43Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
{{MC-Basic&lt;br /&gt;
|SHORT FORM=&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
?&amp;lt;''axis''&amp;gt;.BusNumber&lt;br /&gt;
|AVAILABILITY=&lt;br /&gt;
&lt;br /&gt;
Since Version 4.15.2&amp;lt;br&amp;gt;&lt;br /&gt;
0 - EtherCAT&amp;lt;br&amp;gt;&lt;br /&gt;
1 - CANopen&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
This property sets the field bus to which the axis is connected&lt;br /&gt;
|TYPE=&lt;br /&gt;
Long&lt;br /&gt;
&lt;br /&gt;
|RANGE=&lt;br /&gt;
-1 - Default value, after start up or &amp;quot;reset all&amp;quot;&lt;br /&gt;
0 - EtherCAT&amp;lt;br&amp;gt;&lt;br /&gt;
1 - CANopen&lt;br /&gt;
|UNITS=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|DEFAULT=&lt;br /&gt;
&lt;br /&gt;
|SCOPE=&lt;br /&gt;
Configuration, Task or Terminal.&lt;br /&gt;
&lt;br /&gt;
|LIMITATIONS=&lt;br /&gt;
Till version 4.15.2 Read-only&lt;br /&gt;
&lt;br /&gt;
|EXAMPLE=&lt;br /&gt;
?Axis1.BusNumber&lt;br /&gt;
&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=MC-Basic:axis.DRIVEADDRESS&amp;diff=132752</id>
		<title>MC-Basic:axis.DRIVEADDRESS</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=MC-Basic:axis.DRIVEADDRESS&amp;diff=132752"/>
				<updated>2018-08-07T08:07:47Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|MC-Basic:axis.DRIVEADDRESS}}&lt;br /&gt;
{{MC-Basic&lt;br /&gt;
|SHORT FORM=&lt;br /&gt;
&amp;lt;''axis''&amp;gt;.DAdd&lt;br /&gt;
&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
&amp;lt;''axis''&amp;gt;.DriveAddress = &amp;lt;''drive address''&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
?&amp;lt;''axis''&amp;gt;.DriveAddress&lt;br /&gt;
&lt;br /&gt;
|AVAILABILITY=&lt;br /&gt;
All versions&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
'''* SERCOS:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property associates an axis with a drive. The actual drive address is set by a DIP switch on the drive. If an axis is to be simulated, the drive address of that axis is set to zero. The association may be set explicitly, using this property, or the association may be set during Sercos communication phase 1, when the Sercos driver scans the ring for drives. You must explicitly ask that the ring to be scanned for drives, using the SERCOS.SCAN property.&amp;lt;br&amp;gt;&lt;br /&gt;
'''* CANopen:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property associates an axis with a drive. Usually address is set by a DIP/Rotary switch (located at device/node!) or stored in node's nonvolatile memory.&amp;lt;br&amp;gt;&lt;br /&gt;
The association is set explicitly, using this property. Value reflects 7 LSBs in TPDO/RPDO COBID.&amp;lt;br&amp;gt;&lt;br /&gt;
softMC will start sending/receiving PDOs only when this property is not zero.&amp;lt;br&amp;gt; &lt;br /&gt;
see [[:Category:CANopen:Setup|CAN_SETUP]] for details&amp;lt;br&amp;gt;&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property associates an axis with a drive. Reflects physical (topology) position  of the device (node) on the network, that's, first device has address 1, second is 2 and so on.&amp;lt;br&amp;gt;&lt;br /&gt;
Fist device is the device that is connected to the softMC EtherCAT port.&amp;lt;br&amp;gt;&lt;br /&gt;
The association is set explicitly, using this property.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
see [[:Category:EtherCAT:EC SETUP|EC_SETUP]] for details&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
Property can be set only when Ax.NodeID is set to zero. This is restriction rises from safety considerations}}&amp;lt;br&amp;gt;&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
Ax.NodeID MUST be set to a value different from zero in order to enable the axis}}&amp;lt;br&amp;gt;&lt;br /&gt;
|TYPE=&lt;br /&gt;
Long&lt;br /&gt;
&lt;br /&gt;
|RANGE=&lt;br /&gt;
0 to 254&lt;br /&gt;
&lt;br /&gt;
|UNITS=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|DEFAULT=&lt;br /&gt;
0&lt;br /&gt;
&lt;br /&gt;
|SCOPE=&lt;br /&gt;
Task or Terminal&lt;br /&gt;
&lt;br /&gt;
|LIMITATIONS=&lt;br /&gt;
'''* SERCOS:'''&amp;lt;br&amp;gt;&lt;br /&gt;
The physical address is explicitly set only during communication phase 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Property can be set only in PREOP mode.&lt;br /&gt;
Property can be set only when Ax.NodeID is set to zero. This is restriction rises from safety considerations&lt;br /&gt;
|EXAMPLE=&lt;br /&gt;
a1.dadd = 10&lt;br /&gt;
&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
* [[MC-Basic:axis.NODEID|axis.NODEID]]&lt;br /&gt;
* [[MC-Basic:axis.SIMULATED|axis.SIMULATED]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=MC-Basic:axis.DRIVEADDRESS&amp;diff=132751</id>
		<title>MC-Basic:axis.DRIVEADDRESS</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=MC-Basic:axis.DRIVEADDRESS&amp;diff=132751"/>
				<updated>2018-08-07T08:06:23Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
{{MC-Basic&lt;br /&gt;
|SHORT FORM=&lt;br /&gt;
&amp;lt;''axis''&amp;gt;.DAdd&lt;br /&gt;
&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
&amp;lt;''axis''&amp;gt;.DriveAddress = &amp;lt;''drive address''&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
?&amp;lt;''axis''&amp;gt;.DriveAddress&lt;br /&gt;
&lt;br /&gt;
|AVAILABILITY=&lt;br /&gt;
All versions&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
'''* SERCOS:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property associates an axis with a drive. The actual drive address is set by a DIP switch on the drive. If an axis is to be simulated, the drive address of that axis is set to zero. The association may be set explicitly, using this property, or the association may be set during Sercos communication phase 1, when the Sercos driver scans the ring for drives. You must explicitly ask that the ring to be scanned for drives, using the SERCOS.SCAN property.&amp;lt;br&amp;gt;&lt;br /&gt;
'''* CANopen:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property associates an axis with a drive. Usually address is set by a DIP/Rotary switch (located at device/node!) or stored in node's nonvolatile memory.&amp;lt;br&amp;gt;&lt;br /&gt;
The association is set explicitly, using this property. Value reflects 7 LSBs in TPDO/RPDO COBID.&amp;lt;br&amp;gt;&lt;br /&gt;
softMC will start sending/receiving PDOs only when this property is not zero.&amp;lt;br&amp;gt; &lt;br /&gt;
see [[:Category:CANopen:Setup|CAN_SETUP]] for details&amp;lt;br&amp;gt;&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property associates an axis with a drive. Reflects physical (topology) position  of the device (node) on the network, that's, first device has address 1, second is 2 and so on.&amp;lt;br&amp;gt;&lt;br /&gt;
Fist device is the device that is connected to the softMC EtherCAT port.&amp;lt;br&amp;gt;&lt;br /&gt;
The association is set explicitly, using this property.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
see [[:Category:EtherCAT:EC SETUP|EC_SETUP]] for details&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
Property can be set only when Ax.NodeID is set to zero. This is restriction rises from safety considerations}}&amp;lt;br&amp;gt;&lt;br /&gt;
|TYPE=&lt;br /&gt;
Long&lt;br /&gt;
&lt;br /&gt;
|RANGE=&lt;br /&gt;
0 to 254&lt;br /&gt;
&lt;br /&gt;
|UNITS=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|DEFAULT=&lt;br /&gt;
0&lt;br /&gt;
&lt;br /&gt;
|SCOPE=&lt;br /&gt;
Task or Terminal&lt;br /&gt;
&lt;br /&gt;
|LIMITATIONS=&lt;br /&gt;
'''* SERCOS:'''&amp;lt;br&amp;gt;&lt;br /&gt;
The physical address is explicitly set only during communication phase 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Property can be set only in PREOP mode.&lt;br /&gt;
Property can be set only when Ax.NodeID is set to zero. This is restriction rises from safety considerations&lt;br /&gt;
|EXAMPLE=&lt;br /&gt;
a1.dadd = 10&lt;br /&gt;
&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
* [[MC-Basic:axis.NODEID|axis.NODEID]]&lt;br /&gt;
* [[MC-Basic:axis.SIMULATED|axis.SIMULATED]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=MC-Basic:axis.DRIVEADDRESS&amp;diff=132750</id>
		<title>MC-Basic:axis.DRIVEADDRESS</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=MC-Basic:axis.DRIVEADDRESS&amp;diff=132750"/>
				<updated>2018-08-07T08:05:46Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
{{MC-Basic&lt;br /&gt;
|SHORT FORM=&lt;br /&gt;
&amp;lt;''axis''&amp;gt;.DAdd&lt;br /&gt;
&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
&amp;lt;''axis''&amp;gt;.DriveAddress = &amp;lt;''drive address''&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
?&amp;lt;''axis''&amp;gt;.DriveAddress&lt;br /&gt;
&lt;br /&gt;
|AVAILABILITY=&lt;br /&gt;
All versions&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
'''* SERCOS:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property associates an axis with a drive. The actual drive address is set by a DIP switch on the drive. If an axis is to be simulated, the drive address of that axis is set to zero. The association may be set explicitly, using this property, or the association may be set during Sercos communication phase 1, when the Sercos driver scans the ring for drives. You must explicitly ask that the ring to be scanned for drives, using the SERCOS.SCAN property.&amp;lt;br&amp;gt;&lt;br /&gt;
'''* CANopen:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property associates an axis with a drive. Usually address is set by a DIP/Rotary switch (located at device/node!) or stored in node's nonvolatile memory.&amp;lt;br&amp;gt;&lt;br /&gt;
The association is set explicitly, using this property. Value reflects 7 LSBs in TPDO/RPDO COBID.&amp;lt;br&amp;gt;&lt;br /&gt;
softMC will start sending/receiving PDOs only when this property is not zero.&amp;lt;br&amp;gt; &lt;br /&gt;
see [[:Category:CANopen:Setup|CAN_SETUP]] for details&amp;lt;br&amp;gt;&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property associates an axis with a drive. Reflects physical (topology) position  of the device (node) on the network, that's, first device has address 1, second is 2 and so on.&amp;lt;br&amp;gt;&lt;br /&gt;
Fist device is the device that is connected to the softMC EtherCAT port.&amp;lt;br&amp;gt;&lt;br /&gt;
The association is set explicitly, using this property.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
see [[:Category:EtherCAT:EC SETUP|EC_SETUP]] for details&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
Property can be set only when Ax.NodeID is set to zero. This is restriction rises from safety considerations}}&amp;lt;br&amp;gt;&lt;br /&gt;
|TYPE=&lt;br /&gt;
Long&lt;br /&gt;
&lt;br /&gt;
|RANGE=&lt;br /&gt;
0 to 254&lt;br /&gt;
&lt;br /&gt;
|UNITS=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|DEFAULT=&lt;br /&gt;
0&lt;br /&gt;
&lt;br /&gt;
|SCOPE=&lt;br /&gt;
Task or Terminal&lt;br /&gt;
&lt;br /&gt;
|LIMITATIONS=&lt;br /&gt;
'''* SERCOS:'''&amp;lt;br&amp;gt;&lt;br /&gt;
The physical address is explicitly set only during communication phase 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Property can be set only in PREOP mode.&lt;br /&gt;
|EXAMPLE=&lt;br /&gt;
a1.dadd = 10&lt;br /&gt;
&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
* [[MC-Basic:axis.NODEID|axis.NODEID]]&lt;br /&gt;
* [[MC-Basic:axis.SIMULATED|axis.SIMULATED]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=MC-Basic:axis.NODEID&amp;diff=132749</id>
		<title>MC-Basic:axis.NODEID</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=MC-Basic:axis.NODEID&amp;diff=132749"/>
				<updated>2018-08-07T07:51:10Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages|MC-Basic:axis.NODEID}}&lt;br /&gt;
{{MC-Basic&lt;br /&gt;
&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
&amp;lt;''axis''&amp;gt;.NodeId = &amp;lt;''Node Id''&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
?&amp;lt;''axis''&amp;gt;.NodeId&lt;br /&gt;
&lt;br /&gt;
|AVAILABILITY=&lt;br /&gt;
From 0.4.18.2r5&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property is meant for use with Multi Axis drives, that is, a motion drive that appears as a single EtherCAT slave but can drive more than one motor.&amp;lt;br&amp;gt;&lt;br /&gt;
In this case multiple axes can share the same Drive Address but are distinguished by Node ID.&amp;lt;br&amp;gt;&lt;br /&gt;
For example, if MC is connected to 4 motion drives and the second drive is connected to 3 motors, the axes properties can be assigned as follows:&amp;lt;br&amp;gt;&lt;br /&gt;
A1.Dadd = 1,  A1.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A2.Dadd = 2,  A2.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A3.Dadd = 2,  A3.NodeID = 2&amp;lt;br&amp;gt;&lt;br /&gt;
A4.Dadd = 2,  A4.NodeID = 3&amp;lt;br&amp;gt;&lt;br /&gt;
A5.Dadd = 3,  A5.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A6.Dadd = 4,  A6.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
see [[:Category:EtherCAT:EC SETUP|EC_SETUP]] for details&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
Property can be set only after Ax.Dadd is already set (different from zero)}}&amp;lt;br&amp;gt;&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
NodeID MUST be set to a value different from zero in order to enable the axis}}&amp;lt;br&amp;gt;&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
In case of a regular single axis drive, the user must assign NodeID to 1. It is NOT done by default due to safety considerations}}&amp;lt;br&amp;gt;&lt;br /&gt;
|TYPE=&lt;br /&gt;
Long&lt;br /&gt;
&lt;br /&gt;
|RANGE=&lt;br /&gt;
0 to 8&lt;br /&gt;
&lt;br /&gt;
|UNITS=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|DEFAULT=&lt;br /&gt;
0&lt;br /&gt;
&lt;br /&gt;
|SCOPE=&lt;br /&gt;
Task or Terminal&lt;br /&gt;
&lt;br /&gt;
|LIMITATIONS=&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Property can be set only after Ax.Dadd is already set (different from zero)&amp;lt;br&amp;gt;&lt;br /&gt;
NodeID MUST be set to a value different from zero in order to enable the axis&amp;lt;br&amp;gt;&lt;br /&gt;
In case of a regular single axis drive, the user must assign NodeID to 1. It is NOT done by default due to safety considerations&amp;lt;br&amp;gt;&lt;br /&gt;
|EXAMPLE=&lt;br /&gt;
a1.NodeId = 3&lt;br /&gt;
&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
&lt;br /&gt;
* [[MC-Basic:axis.DRIVEADDRESS|axis.DRIVEADDRESS]]&lt;br /&gt;
* [[MC-Basic:axis.SIMULATED|axis.SIMULATED]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=MC-Basic:axis.DRIVEADDRESS&amp;diff=132748</id>
		<title>MC-Basic:axis.DRIVEADDRESS</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=MC-Basic:axis.DRIVEADDRESS&amp;diff=132748"/>
				<updated>2018-08-07T07:51:03Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
{{MC-Basic&lt;br /&gt;
|SHORT FORM=&lt;br /&gt;
&amp;lt;''axis''&amp;gt;.DAdd&lt;br /&gt;
&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
&amp;lt;''axis''&amp;gt;.DriveAddress = &amp;lt;''drive address''&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
?&amp;lt;''axis''&amp;gt;.DriveAddress&lt;br /&gt;
&lt;br /&gt;
|AVAILABILITY=&lt;br /&gt;
All versions&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
'''* SERCOS:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property associates an axis with a drive. The actual drive address is set by a DIP switch on the drive. If an axis is to be simulated, the drive address of that axis is set to zero. The association may be set explicitly, using this property, or the association may be set during Sercos communication phase 1, when the Sercos driver scans the ring for drives. You must explicitly ask that the ring to be scanned for drives, using the SERCOS.SCAN property.&amp;lt;br&amp;gt;&lt;br /&gt;
'''* CANopen:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property associates an axis with a drive. Usually address is set by a DIP/Rotary switch (located at device/node!) or stored in node's nonvolatile memory.&amp;lt;br&amp;gt;&lt;br /&gt;
The association is set explicitly, using this property. Value reflects 7 LSBs in TPDO/RPDO COBID.&amp;lt;br&amp;gt;&lt;br /&gt;
softMC will start sending/receiving PDOs only when this property is not zero.&amp;lt;br&amp;gt; &lt;br /&gt;
see [[:Category:CANopen:Setup|CAN_SETUP]] for details&amp;lt;br&amp;gt;&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property associates an axis with a drive. Reflects physical (topology) position  of the device (node) on the network, that's, first device has address 1, second is 2 and so on.&amp;lt;br&amp;gt;&lt;br /&gt;
Fist device is the device that is connected to the softMC EtherCAT port.&amp;lt;br&amp;gt;&lt;br /&gt;
The association is set explicitly, using this property.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
see [[:Category:EtherCAT:SETUP-EC|EC_SETUP]] for details&lt;br /&gt;
|TYPE=&lt;br /&gt;
Long&lt;br /&gt;
&lt;br /&gt;
|RANGE=&lt;br /&gt;
0 to 254&lt;br /&gt;
&lt;br /&gt;
|UNITS=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|DEFAULT=&lt;br /&gt;
0&lt;br /&gt;
&lt;br /&gt;
|SCOPE=&lt;br /&gt;
Task or Terminal&lt;br /&gt;
&lt;br /&gt;
|LIMITATIONS=&lt;br /&gt;
'''* SERCOS:'''&amp;lt;br&amp;gt;&lt;br /&gt;
The physical address is explicitly set only during communication phase 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Property can be set only in PREOP mode.&lt;br /&gt;
|EXAMPLE=&lt;br /&gt;
a1.dadd = 10&lt;br /&gt;
&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
* [[MC-Basic:axis.NODEID|axis.NODEID]]&lt;br /&gt;
* [[MC-Basic:axis.SIMULATED|axis.SIMULATED]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=MC-Basic:axis.NODEID&amp;diff=132747</id>
		<title>MC-Basic:axis.NODEID</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=MC-Basic:axis.NODEID&amp;diff=132747"/>
				<updated>2018-08-07T07:49:46Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
{{MC-Basic&lt;br /&gt;
&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
&amp;lt;''axis''&amp;gt;.NodeId = &amp;lt;''Node Id''&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
?&amp;lt;''axis''&amp;gt;.NodeId&lt;br /&gt;
&lt;br /&gt;
|AVAILABILITY=&lt;br /&gt;
From 0.4.18.2r5&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property is meant for use with Multi Axis drives, that is, a motion drive that appears as a single EtherCAT slave but can drive more than one motor.&amp;lt;br&amp;gt;&lt;br /&gt;
In this case multiple axes can share the same Drive Address but are distinguished by Node ID.&amp;lt;br&amp;gt;&lt;br /&gt;
For example, if MC is connected to 4 motion drives and the second drive is connected to 3 motors, the axes properties can be assigned as follows:&amp;lt;br&amp;gt;&lt;br /&gt;
A1.Dadd = 1,  A1.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A2.Dadd = 2,  A2.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A3.Dadd = 2,  A3.NodeID = 2&amp;lt;br&amp;gt;&lt;br /&gt;
A4.Dadd = 2,  A4.NodeID = 3&amp;lt;br&amp;gt;&lt;br /&gt;
A5.Dadd = 3,  A5.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A6.Dadd = 4,  A6.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
see [[:Category:EtherCAT:EC SETUP|EC_SETUP]] for details&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
Property can be set only after Ax.Dadd is already set (different from zero)}}&amp;lt;br&amp;gt;&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
NodeID MUST be set to a value different from zero in order to enable the axis}}&amp;lt;br&amp;gt;&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
In case of a regular single axis drive, the user must assign NodeID to 1. It is NOT done by default due to safety considerations}}&amp;lt;br&amp;gt;&lt;br /&gt;
|TYPE=&lt;br /&gt;
Long&lt;br /&gt;
&lt;br /&gt;
|RANGE=&lt;br /&gt;
0 to 8&lt;br /&gt;
&lt;br /&gt;
|UNITS=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|DEFAULT=&lt;br /&gt;
0&lt;br /&gt;
&lt;br /&gt;
|SCOPE=&lt;br /&gt;
Task or Terminal&lt;br /&gt;
&lt;br /&gt;
|LIMITATIONS=&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Property can be set only after Ax.Dadd is already set (different from zero)&amp;lt;br&amp;gt;&lt;br /&gt;
NodeID MUST be set to a value different from zero in order to enable the axis&lt;br /&gt;
|EXAMPLE=&lt;br /&gt;
a1.NodeId = 3&lt;br /&gt;
&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
&lt;br /&gt;
* [[MC-Basic:axis.DRIVEADDRESS|axis.DRIVEADDRESS]]&lt;br /&gt;
* [[MC-Basic:axis.SIMULATED|axis.SIMULATED]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=MC-Basic:axis.NODEID&amp;diff=132746</id>
		<title>MC-Basic:axis.NODEID</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=MC-Basic:axis.NODEID&amp;diff=132746"/>
				<updated>2018-08-07T07:46:27Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
{{MC-Basic&lt;br /&gt;
&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
&amp;lt;''axis''&amp;gt;.NodeId = &amp;lt;''Node Id''&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
?&amp;lt;''axis''&amp;gt;.NodeId&lt;br /&gt;
&lt;br /&gt;
|AVAILABILITY=&lt;br /&gt;
From 0.4.18.2r5&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property is meant for use with Multi Axis drives, that is, a motion drive that appears as a single EtherCAT slave but can drive more than one motor.&amp;lt;br&amp;gt;&lt;br /&gt;
In this case multiple axes can share the same Drive Address but are distinguished by Node ID.&amp;lt;br&amp;gt;&lt;br /&gt;
For example, if MC is connected to 4 motion drives and the second drive is connected to 3 motors, the axes properties can be assigned as follows:&amp;lt;br&amp;gt;&lt;br /&gt;
A1.Dadd = 1,  A1.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A2.Dadd = 2,  A2.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A3.Dadd = 2,  A3.NodeID = 2&amp;lt;br&amp;gt;&lt;br /&gt;
A4.Dadd = 2,  A4.NodeID = 3&amp;lt;br&amp;gt;&lt;br /&gt;
A5.Dadd = 3,  A5.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A6.Dadd = 4,  A6.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
see [[:Category:EtherCAT:EC SETUP|EC_SETUP]] for details&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
Property can be set only after Ax.Dadd is already set (different from zero)}}&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
NodeID MUST be set to a value different from zero in order to enable the axis}}&lt;br /&gt;
|TYPE=&lt;br /&gt;
Long&lt;br /&gt;
&lt;br /&gt;
|RANGE=&lt;br /&gt;
0 to 8&lt;br /&gt;
&lt;br /&gt;
|UNITS=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|DEFAULT=&lt;br /&gt;
0&lt;br /&gt;
&lt;br /&gt;
|SCOPE=&lt;br /&gt;
Task or Terminal&lt;br /&gt;
&lt;br /&gt;
|LIMITATIONS=&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Property can be set only after Ax.Dadd is already set (different from zero)&amp;lt;br&amp;gt;&lt;br /&gt;
NodeID MUST be set to a value different from zero in order to enable the axis&lt;br /&gt;
|EXAMPLE=&lt;br /&gt;
a1.NodeId = 3&lt;br /&gt;
&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
&lt;br /&gt;
* [[MC-Basic:axis.DRIVEADDRESS|axis.DRIVEADDRESS]]&lt;br /&gt;
* [[MC-Basic:axis.SIMULATED|axis.SIMULATED]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=MC-Basic:axis.NODEID&amp;diff=132745</id>
		<title>MC-Basic:axis.NODEID</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=MC-Basic:axis.NODEID&amp;diff=132745"/>
				<updated>2018-08-07T07:42:59Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
{{MC-Basic&lt;br /&gt;
&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
&amp;lt;''axis''&amp;gt;.NodeId = &amp;lt;''Node Id''&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
?&amp;lt;''axis''&amp;gt;.NodeId&lt;br /&gt;
&lt;br /&gt;
|AVAILABILITY=&lt;br /&gt;
From 0.4.18.2r5&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property is meant for use with Multi Axis drives, that is, a motion drive that appears as a single EtherCAT slave but can drive more than one motor.&amp;lt;br&amp;gt;&lt;br /&gt;
In this case multiple axes can share the same Drive Address but are distinguished by Node ID.&amp;lt;br&amp;gt;&lt;br /&gt;
For example, if MC is connected to 4 motion drives and the second drive is connected to 3 motors, the axes properties can be assigned as follows:&amp;lt;br&amp;gt;&lt;br /&gt;
A1.Dadd = 1,  A1.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A2.Dadd = 2,  A2.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A3.Dadd = 2,  A3.NodeID = 2&amp;lt;br&amp;gt;&lt;br /&gt;
A4.Dadd = 2,  A4.NodeID = 3&amp;lt;br&amp;gt;&lt;br /&gt;
A5.Dadd = 3,  A5.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A6.Dadd = 4,  A6.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
see [[:Category:EtherCAT:EC SETUP|EC_SETUP]] for details&lt;br /&gt;
|TYPE=&lt;br /&gt;
Long&lt;br /&gt;
&lt;br /&gt;
|RANGE=&lt;br /&gt;
0 to 8&lt;br /&gt;
&lt;br /&gt;
|UNITS=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|DEFAULT=&lt;br /&gt;
0&lt;br /&gt;
&lt;br /&gt;
|SCOPE=&lt;br /&gt;
Task or Terminal&lt;br /&gt;
&lt;br /&gt;
|LIMITATIONS=&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Property can be set only after Ax.Dadd is already set (different from zero)&lt;br /&gt;
|EXAMPLE=&lt;br /&gt;
a1.NodeId = 3&lt;br /&gt;
&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
&lt;br /&gt;
* [[MC-Basic:axis.DRIVEADDRESS|axis.DRIVEADDRESS]]&lt;br /&gt;
* [[MC-Basic:axis.SIMULATED|axis.SIMULATED]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=MC-Basic:axis.NODEID&amp;diff=132744</id>
		<title>MC-Basic:axis.NODEID</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=MC-Basic:axis.NODEID&amp;diff=132744"/>
				<updated>2018-08-07T07:42:32Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
{{MC-Basic&lt;br /&gt;
&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
&amp;lt;''axis''&amp;gt;.NodeId = &amp;lt;''Node Id''&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
?&amp;lt;''axis''&amp;gt;.NodeId&lt;br /&gt;
&lt;br /&gt;
|AVAILABILITY=&lt;br /&gt;
From 0.4.18.2r5&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property is meant for use with Multi Axis drives, that is, a motion drive that appears as a single EtherCAT slave but can drive more than one motor.&amp;lt;br&amp;gt;&lt;br /&gt;
In this case multiple axes can share the same Drive Address but are distinguished by Node ID.&amp;lt;br&amp;gt;&lt;br /&gt;
For example, if MC is connected to 4 motion drives and the second drive is connected to 3 motors, the axes properties can be assigned as follows:&amp;lt;br&amp;gt;&lt;br /&gt;
A1.Dadd = 1,  A1.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A2.Dadd = 2,  A2.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A3.Dadd = 2,  A3.NodeID = 2&amp;lt;br&amp;gt;&lt;br /&gt;
A4.Dadd = 2,  A4.NodeID = 3&amp;lt;br&amp;gt;&lt;br /&gt;
A5.Dadd = 3,  A5.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A6.Dadd = 4,  A6.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
see [[EtherCAT:EC_SETUP|EC_SETUP]] for details&lt;br /&gt;
**[[:Category:EtherCAT:EC SETUP|EC_SETUP]]&lt;br /&gt;
|TYPE=&lt;br /&gt;
Long&lt;br /&gt;
&lt;br /&gt;
|RANGE=&lt;br /&gt;
0 to 8&lt;br /&gt;
&lt;br /&gt;
|UNITS=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|DEFAULT=&lt;br /&gt;
0&lt;br /&gt;
&lt;br /&gt;
|SCOPE=&lt;br /&gt;
Task or Terminal&lt;br /&gt;
&lt;br /&gt;
|LIMITATIONS=&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Property can be set only after Ax.Dadd is already set (different from zero)&lt;br /&gt;
|EXAMPLE=&lt;br /&gt;
a1.NodeId = 3&lt;br /&gt;
&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
&lt;br /&gt;
* [[MC-Basic:axis.DRIVEADDRESS|axis.DRIVEADDRESS]]&lt;br /&gt;
* [[MC-Basic:axis.SIMULATED|axis.SIMULATED]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=MC-Basic:axis.NODEID&amp;diff=132743</id>
		<title>MC-Basic:axis.NODEID</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=MC-Basic:axis.NODEID&amp;diff=132743"/>
				<updated>2018-08-07T07:41:23Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
{{MC-Basic&lt;br /&gt;
&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
&amp;lt;''axis''&amp;gt;.NodeId = &amp;lt;''Node Id''&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
?&amp;lt;''axis''&amp;gt;.NodeId&lt;br /&gt;
&lt;br /&gt;
|AVAILABILITY=&lt;br /&gt;
From 0.4.18.2r5&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property is meant for use with Multi Axis drives, that is, a motion drive that appears as a single EtherCAT slave but can drive more than one motor.&amp;lt;br&amp;gt;&lt;br /&gt;
In this case multiple axes can share the same Drive Address but are distinguished by Node ID.&amp;lt;br&amp;gt;&lt;br /&gt;
For example, if MC is connected to 4 motion drives and the second drive is connected to 3 motors, the axes properties can be assigned as follows:&amp;lt;br&amp;gt;&lt;br /&gt;
A1.Dadd = 1,  A1.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A2.Dadd = 2,  A2.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A3.Dadd = 2,  A3.NodeID = 2&amp;lt;br&amp;gt;&lt;br /&gt;
A4.Dadd = 2,  A4.NodeID = 3&amp;lt;br&amp;gt;&lt;br /&gt;
A5.Dadd = 3,  A5.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A6.Dadd = 4,  A6.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
see [[EtherCAT:EC_SETUP|EC_SETUP]] for details&lt;br /&gt;
|TYPE=&lt;br /&gt;
Long&lt;br /&gt;
&lt;br /&gt;
|RANGE=&lt;br /&gt;
0 to 8&lt;br /&gt;
&lt;br /&gt;
|UNITS=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|DEFAULT=&lt;br /&gt;
0&lt;br /&gt;
&lt;br /&gt;
|SCOPE=&lt;br /&gt;
Task or Terminal&lt;br /&gt;
&lt;br /&gt;
|LIMITATIONS=&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Property can be set only after Ax.Dadd is already set (different from zero)&lt;br /&gt;
|EXAMPLE=&lt;br /&gt;
a1.NodeId = 3&lt;br /&gt;
&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
&lt;br /&gt;
* [[MC-Basic:axis.DRIVEADDRESS|axis.DRIVEADDRESS]]&lt;br /&gt;
* [[MC-Basic:axis.SIMULATED|axis.SIMULATED]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=MC-Basic:axis.NODEID&amp;diff=132742</id>
		<title>MC-Basic:axis.NODEID</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=MC-Basic:axis.NODEID&amp;diff=132742"/>
				<updated>2018-08-07T07:13:34Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
{{MC-Basic&lt;br /&gt;
&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
&amp;lt;''axis''&amp;gt;.NodeId = &amp;lt;''Node Id''&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
?&amp;lt;''axis''&amp;gt;.NodeId&lt;br /&gt;
&lt;br /&gt;
|AVAILABILITY=&lt;br /&gt;
From 0.4.18.2r5&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property is meant for use with Multi Axis drives, that is, a motion drive that appears as a single EtherCAT slave but can drive more than one motor.&amp;lt;br&amp;gt;&lt;br /&gt;
In this case multiple axes can share the same Drive Address but are distinguished by Node ID.&amp;lt;br&amp;gt;&lt;br /&gt;
For example, if MC is connected to 4 motion drives and the second drive is connected to 3 motors, the axes properties can be assigned as follows:&amp;lt;br&amp;gt;&lt;br /&gt;
A1.Dadd = 1,  A1.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A2.Dadd = 2,  A2.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A3.Dadd = 2,  A3.NodeID = 2&amp;lt;br&amp;gt;&lt;br /&gt;
A4.Dadd = 2,  A4.NodeID = 3&amp;lt;br&amp;gt;&lt;br /&gt;
A5.Dadd = 3,  A5.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
A6.Dadd = 4,  A6.NodeID = 1&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
see [[:Category:EtherCAT:SETUP-EC|EC_SETUP]] for details&lt;br /&gt;
|TYPE=&lt;br /&gt;
Long&lt;br /&gt;
&lt;br /&gt;
|RANGE=&lt;br /&gt;
0 to 8&lt;br /&gt;
&lt;br /&gt;
|UNITS=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|DEFAULT=&lt;br /&gt;
0&lt;br /&gt;
&lt;br /&gt;
|SCOPE=&lt;br /&gt;
Task or Terminal&lt;br /&gt;
&lt;br /&gt;
|LIMITATIONS=&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Property can be set only after Ax.Dadd is already set (different from zero)&lt;br /&gt;
|EXAMPLE=&lt;br /&gt;
a1.NodeId = 3&lt;br /&gt;
&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
* [[MC-Basic:axis.SIMULATED|axis.SIMULATED]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=MC-Basic:axis.NODEID&amp;diff=132741</id>
		<title>MC-Basic:axis.NODEID</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=MC-Basic:axis.NODEID&amp;diff=132741"/>
				<updated>2018-08-07T07:12:29Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: Created page with &amp;quot;{{Languages}} {{MC-Basic  |SYNTAX= &amp;lt;''axis''&amp;gt;.NodeId = &amp;lt;''Node Id''&amp;gt;&amp;lt;br&amp;gt;  ?&amp;lt;''axis''&amp;gt;.NodeId  |AVAILABILITY= From 0.4.18.2r5  |DESCRIPTION= '''* EtherCAT:'''&amp;lt;br&amp;gt; This property...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
{{MC-Basic&lt;br /&gt;
&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
&amp;lt;''axis''&amp;gt;.NodeId = &amp;lt;''Node Id''&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
?&amp;lt;''axis''&amp;gt;.NodeId&lt;br /&gt;
&lt;br /&gt;
|AVAILABILITY=&lt;br /&gt;
From 0.4.18.2r5&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
This property is meant for use with Multi Axis drives, that is, a motion drive that appears as a single EtherCAT slave but can drive more than one motor.&lt;br /&gt;
In this case multiple axes can share the same Drive Address but are distinguished by Node ID.&lt;br /&gt;
For example, if MC is connected to 4 motion drives and the second drive is connected to 3 motors, the axes properties can be assigned as follows:&lt;br /&gt;
A1.Dadd = 1,  A1.NodeID = 1&lt;br /&gt;
A2.Dadd = 2,  A2.NodeID = 1&lt;br /&gt;
A3.Dadd = 2,  A3.NodeID = 2&lt;br /&gt;
A4.Dadd = 2,  A4.NodeID = 3&lt;br /&gt;
A5.Dadd = 3,  A5.NodeID = 1&lt;br /&gt;
A6.Dadd = 4,  A6.NodeID = 1&lt;br /&gt;
&lt;br /&gt;
see [[:Category:EtherCAT:SETUP-EC|EC_SETUP]] for details&lt;br /&gt;
|TYPE=&lt;br /&gt;
Long&lt;br /&gt;
&lt;br /&gt;
|RANGE=&lt;br /&gt;
0 to 8&lt;br /&gt;
&lt;br /&gt;
|UNITS=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|DEFAULT=&lt;br /&gt;
0&lt;br /&gt;
&lt;br /&gt;
|SCOPE=&lt;br /&gt;
Task or Terminal&lt;br /&gt;
&lt;br /&gt;
|LIMITATIONS=&lt;br /&gt;
'''* EtherCAT:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Property can be set only after Ax.Dadd is already set (different from zero)&lt;br /&gt;
|EXAMPLE=&lt;br /&gt;
a1.NodeId = 3&lt;br /&gt;
&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
* [[MC-Basic:axis.SIMULATED|axis.SIMULATED]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Program_Examples&amp;diff=131196</id>
		<title>Program Examples</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Program_Examples&amp;diff=131196"/>
				<updated>2017-08-30T07:01:21Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Languages}}&lt;br /&gt;
= Getting Started = &lt;br /&gt;
* [[Getting_Started_with_MC-Basic_and_ControlStudio|Getting Started with MC-Basic and ControlStudio]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Communication =&lt;br /&gt;
* [[Program Examples:Serial Com:Serial Com Example|Program Example - Serial COM]] - How to setup a serial connection&lt;br /&gt;
* [[Program Examples:TCP IP:TCPIP Simple Server|Program Example - TCP/IP Simple Server]] - How to setup a simple TCP-IP server&lt;br /&gt;
* [[Program Examples:TCP IP:TCPIP Simple Client|Program Example - TCP/IP Simple Client]] - How to setup a simple TCP-IP client&lt;br /&gt;
* [[Program Examples:TCP IP:TCPIP Multi Server|Program Example - TCP/IP Multi Server]] - How to setup a TCP-IP server that opens connections with multiple clients&lt;br /&gt;
* [[Program_Examples:TCP_IP:TCPIP_TelNet_Server|Program Example - TCP/IP TelNet Server]] - How to setup a TCP-IP TelNet server with simple parser&lt;br /&gt;
* [[Program_Examples:TCP_IP:TCPIP_Winsock_Client|Program Example - TCP/IP windows socket client]] - An example written in C language, corresponds to the &lt;br /&gt;
* [[Program_Examples:TCP_IP:TCPIP_TelNet_Server|TCP/IP TelNet Server]] example.&lt;br /&gt;
&lt;br /&gt;
= File handling=&lt;br /&gt;
* [[Program Examples:File Handling:Open Read Write|Program Example - File Handling - Open Read Write]] - How to open a file with different permissions&lt;br /&gt;
* [[Virtual Entry Station (VES)|Program Example - Virtual Entry Station (VES)]]&lt;br /&gt;
= Motion Bus =&lt;br /&gt;
* [[Program_Examples:CANOpen:DS402_CAN_Drive_Setup|Program Example - DS402 CAN Drive Setup]] - How to setup drive for cyclic synchronous position operation&lt;br /&gt;
&lt;br /&gt;
= HMI =&lt;br /&gt;
* [[Program_Examples:Operate_softMC_3_with_HMI| Program Examples - HMI]] - how to configure HMI with softMC 3&lt;br /&gt;
&lt;br /&gt;
= Caming Examples =&lt;br /&gt;
* [[Program_Examples:Create_Motion:CAM_Table|Program Examples - Create CAM table and move axes]]&lt;br /&gt;
* [[Program Examples:Camming by Virtual Master|Program Examples - Caming by Virtual Master]]&lt;br /&gt;
* [[Program_Examples:Reverse engineering for cam table|Program Examples - Reverse engineering for cam table]]&lt;br /&gt;
* [[Program_Examples:Cam table with shutdown and restart|Program Examples - Cam table with shutdown and restart]]&lt;br /&gt;
* [[Cut To Length (Punching) Application|Program Examples - Cut To Length (Punching) Application]]&lt;br /&gt;
* [[Flying Shear Application|Program Examples - Flying Shear Application]]&lt;br /&gt;
&lt;br /&gt;
= Motion Examples =&lt;br /&gt;
* [[Axis Setup Procedure|Program Example - Axis Setup]] - How to set up the basic configuration of an axis.&lt;br /&gt;
* [[PLS_SETUP_PROCEDURE|Program Example - PLS Setup Procedure]] - How to set up a PLS data structure.&lt;br /&gt;
* [[Defining_Cartesian_Groups|Program Example - Defining Cartesian Groups]] - How to set up an XYZ system.&lt;br /&gt;
* [[Program Examples:Helical Interpolation|Program Examples - Helical Interpolation]] - Circle Demo&lt;br /&gt;
* [[Program_Examples:Backlash_Compensation|Program Examples - Backlash Compensation]] - Position Backlash Compensation&lt;br /&gt;
* [[Program_Examples:Backlash_Compensation_Table|Program Examples - Backlash Compensation using Compensation Tables]] - Position Backlash Compensation using compensation tables&lt;br /&gt;
* [[Program_Examples:Homing|Program Examples - Homing]] - How to set homing parameters and issue a homing procedure&lt;br /&gt;
* [[Program_Examples:Create_Motion:Position_Mode|Program Examples - Move Axis in Position Mode]]&lt;br /&gt;
* [[Program_Examples:Create_Motion:Velocity_Mode|Program Examples - Jog Axis in Velocity Mode]]&lt;br /&gt;
* [[Program_Examples:Create_Motion:Torque_Mode|Program Examples - Issue a Torque Command to an Axis in Torque Mode]]&lt;br /&gt;
* [[Program_Examples:Defining_a_Cartesian_Group|Program_Examples - Defining a Cartesian Group]]&lt;br /&gt;
* [[Program_Examples:Setting_Up_an_Axis|Program_Examples - Setting Up an Axis]]&lt;br /&gt;
* [[Program_Examples:Robot tool calibration|Program_Examples - Robot tool calibration]]&lt;br /&gt;
* [[Program_Examples:CT without buffer|Program_Examples - CT without buffer]]&lt;br /&gt;
* [[Program_Examples:Group Blending|Program_Examples - Group Blending]]&lt;br /&gt;
* [[Program_Examples:Robot Circle Command|Program_Examples - Robot Circle Command]]&lt;br /&gt;
* [[Program_Examples:Path-PLS|Program_Examples - Path-PLS]]&lt;br /&gt;
* [[Program_Examples:Cartesian Gearing|Program_Examples - Cartesian Gearing]]&lt;br /&gt;
* [[Program_Examples_-_Robot_Pick_and_Place_(P%26P)|Program_Examples - Robot Pick and Place (P&amp;amp;P)]]&lt;br /&gt;
* [[Program_Examples_-_Robot_Helix_motion|Program_Examples - Robot Helix motion]]&lt;br /&gt;
&amp;lt;!--* [[Program_Examples:Cyclic_recording_of_one_Axis|Program_Examples - Cyclic recording of one Axis]]--&amp;gt;&lt;br /&gt;
* [[Program_Examples:Cyclic_recording_of_single_Axis|Program_Examples - Cyclic recording of single Axis]]&lt;br /&gt;
* [[PIPEMODE_Examples: library and motion commands | PIPEMODE Examples - Library and Motion Commands]]&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Advanced (Expert)=&lt;br /&gt;
* [[Program_Examples:Visualization with RoboDK|Program_Example - Visualization with RoboDK]]&lt;br /&gt;
* [[Program_Examples:sys_log|Program Examples - sys.log]] - How to send log messages from MC-Basic context to Linux sys.log&lt;br /&gt;
* [[Program_Examples:Shared_Objects|Program Examples - Shared Objects]] - How to create, link and use shared objects with softMC&lt;br /&gt;
* [[Program_Examples:real time motion event tracer |Program Example - real time motion event tracer]] - How to trace internal motion events&lt;br /&gt;
* [[Program_Examples:Sci_Lab_interface| Program_Example - Sci Lab interface]] - Plotting softMC rec files in SciLab&lt;br /&gt;
* [[Program_Examples:Octave_interface| Program_Example - Octave interface]] - Plotting softMC rec files in Octave&lt;br /&gt;
* [[Program_Examples:User Kinematics|Program_Example - User Kinematics - '''Advanced!''']]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=EtherCAT:EC_ASSOCIATE_PDO_TO_SYS_DIO&amp;diff=126913</id>
		<title>EtherCAT:EC ASSOCIATE PDO TO SYS DIO</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=EtherCAT:EC_ASSOCIATE_PDO_TO_SYS_DIO&amp;diff=126913"/>
				<updated>2017-04-13T08:40:00Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:EtherCAT-Function&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
This subroutine associates between System digital IOs to an EtherCAT slave IOs.&amp;lt;br/&amp;gt;&lt;br /&gt;
This allows the user to handle the slave's digital IOs by using the following syntax:&amp;lt;br/&amp;gt;&lt;br /&gt;
?Sys.din[&amp;lt;first system digital input bit&amp;gt;][&amp;lt;Range&amp;gt;]&amp;lt;br/&amp;gt;&lt;br /&gt;
Sys.dout[&amp;lt;first system digital output bit&amp;gt;][&amp;lt;Range&amp;gt;] = &amp;lt;value&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
It is up to the user to assign system IOs carefully, and make sure that the same system IO isn't mapped&lt;br /&gt;
to more than one IO (of a motion drive or an IO module).&lt;br /&gt;
&lt;br /&gt;
Behavior is UNDEFINED if this rule is broken !!!}}&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|This subroutine must be invoked before the EtherCAT master is started. Refer to [[:Category:EtherCAT:ECAT_GENERAL_GUIDE|EtherCAT General Guide]] and [[:Category:EtherCAT:EC SETUP|Setup EtherCAT]] for more information}}&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
|INPUT=&lt;br /&gt;
slave address, PDO index, PDO sub-index, First SYSTEM digital output.&amp;lt;br/&amp;gt;&lt;br /&gt;
range - number of digital IOs mapped to the relevant PDO&amp;lt;br/&amp;gt;&lt;br /&gt;
inherent_offset - In some slaves, like the STX CDHD, the PDO's size is 32 bits but the DIOs are mapped from 16 to 32, therefore the inherent offset is 16.&lt;br /&gt;
&lt;br /&gt;
|OUTPUT=&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
|RETURN VALUE=&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
|DECLARATION=&lt;br /&gt;
public sub EC_ASSOCIATE_PDO_TO_SYS_DIO(byval slaveAddr as long, byval PDOindex as long, byval PDOsubindex as long, byval systemDIOnumber as long, byval range as long, byval inherent_offset as long)&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
call EC_ASSOCIATE_PDO_TO_SYS_DIO(&amp;lt;Slave address&amp;gt;, &amp;lt;PDO index&amp;gt;, &amp;lt;PDOS sub-index&amp;gt;, &amp;lt;first SYSTEM digital output&amp;gt;, &amp;lt;range&amp;gt;, &amp;lt;inherent offset&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
|EXAMPLE=&lt;br /&gt;
call EC_ASSOCIATE_PDO_TO_SYS_DIO(drive_addr, 0x60FD, 0x0, drive_addr*100, 11, 16)  '  16 - inherent offset in 60FD to digital inputs&amp;lt;br/&amp;gt;&lt;br /&gt;
call EC_ASSOCIATE_PDO_TO_SYS_DIO(drive_addr, 0x60FE, 0x1, drive_addr*100, 6, 16)  '  16 - inherent offset in 60FE to digital outputs&amp;lt;br/&amp;gt;&lt;br /&gt;
If drive_addr == 3, the last example maps the drive's first digital output to the system digital output bit number 300,&amp;lt;br/&amp;gt;&lt;br /&gt;
drive's second digital output to system digital output bit number 301, and so on until Drive Dout 11 and System DOut 311.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
* [[:Category:EtherCAT:ECAT_GENERAL_GUIDE|ECAT_GENERAL_GUIDE]]&lt;br /&gt;
* [[EtherCAT:EC_INSTALL_STX_CDHD|EC_INSTALL_STX_CDHD]]&lt;br /&gt;
* [[EtherCAT:DIGITAL-IOS|DIGITAL-IOS]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=MC-Basic:TORQUE&amp;diff=125942</id>
		<title>MC-Basic:TORQUE</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=MC-Basic:TORQUE&amp;diff=125942"/>
				<updated>2016-06-19T14:10:49Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{MC-Basic&lt;br /&gt;
|SHORT FORM= Torque&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
Torque &amp;lt;''axis''&amp;gt; &amp;lt;''Torque Value''&amp;gt; {TorqueChangeRatio=&amp;lt;''value''&amp;gt;} {TorqueChangeRatioMax=&amp;lt;''value''&amp;gt;} {StartType = Generator-Completed, Immediate, Super-Immediate}&lt;br /&gt;
|AVAILABILITY= Since Version 4.9.0&lt;br /&gt;
|DESCRIPTION= &lt;br /&gt;
&lt;br /&gt;
*If executed in a mode different than TORQUEMODE a note will be thrown, but the command will be executed as usual&lt;br /&gt;
&lt;br /&gt;
*Interpolates torque command ([[MC-Basic:axis.TORQUECOMMAND|TCMD]]) value from its initial value to the given torque value. The interpolation is done using the value of '''min([[MC-Basic:axis.TORQUECHANGERATIO|TorqueChangeRatio]],[[MC-Basic:axis.TORQUECHANGERATIOMAX|TorqueChangeRatioMax]])''' value as a rate of TCMD value change. No additional smoothing is done.&lt;br /&gt;
&lt;br /&gt;
*The torque interpolation is done using same mechanisms as motion interpolation. Depending on the value of &amp;lt;''axis''&amp;gt;.StartType the interpolation will start after the previous torque command was given or immediately (same rules as move command).The value of inpos for the starttype will be ignored and GCOMP will be used instead.&lt;br /&gt;
&lt;br /&gt;
*During execution the value of isMoving will be nonzero. Values of axis PCMD, VCMD, ACCELCOMMAND are not affected.&lt;br /&gt;
 &lt;br /&gt;
|TYPE=&lt;br /&gt;
&amp;lt;''Torque Value''&amp;gt; - double&lt;br /&gt;
|RANGE=&lt;br /&gt;
|UNITS=&lt;br /&gt;
|DEFAULT=&lt;br /&gt;
|SCOPE=&lt;br /&gt;
|LIMITATIONS= &lt;br /&gt;
|EXAMPLE= Torque Ax1 10.1 ''StartType=Immediate''&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
* [[MC-Basic:axis.OPMODE|OPMODE]]&lt;br /&gt;
* [[MC-Basic:axis.TORQUECHANGERATIO|TORQUECHANGERATIO]]&lt;br /&gt;
* [[MC-Basic:axis.TORQUECHANGERATIOMAX|TORQUECHANGERATIOMAX]]&lt;br /&gt;
* [[MC-Basic:axis.SUMTORQUE|SUMTORQUE]]&lt;br /&gt;
&lt;br /&gt;
* [[MC-Basic:axis.TORQUECOMMAND|TORQUECOMMAND]]&lt;br /&gt;
* [[MC-Basic:axis.COUNTTORQUECOMMAND|COUNTTORQUECOMMAND]]&lt;br /&gt;
&lt;br /&gt;
* [[MC-Basic:axis.TORQUEADDCOMMAND|TORQUEADDCOMMAND]]&lt;br /&gt;
* [[MC-Basic:axis.COUNTTORQUEADDITIVECOMMAND|COUNTTORQUEADDITIVECOMMAND]]&lt;br /&gt;
&lt;br /&gt;
* [[MC-Basic:axis.TORQUEFEEDBACK|TORQUEFEEDBACK]]&lt;br /&gt;
* [[MC-Basic:axis.COUNTTORQUEFEEDBACK|COUNTTORQUEFEEDBACK]]&lt;br /&gt;
&lt;br /&gt;
* [[MC-Basic:axis.TORQUEDRIVECOMMAND|TORQUEDRIVECOMMAND]]&lt;br /&gt;
* [[MC-Basic:axis.COUNTTORQUEDRIVECOMMAND|COUNTTORQUEDRIVECOMMAND]]&lt;br /&gt;
&lt;br /&gt;
* [[OperationalModes| Operational Modes]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
* ''[[AXY:MC_Operational_Modes | MC Operational Modes]]''&lt;br /&gt;
* ''[[AXY:Operational_Modes | Operational Modes]]''&lt;br /&gt;
}}&lt;br /&gt;
[[Category:OperationalModes]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=MC-Basic:TORQUE&amp;diff=125941</id>
		<title>MC-Basic:TORQUE</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=MC-Basic:TORQUE&amp;diff=125941"/>
				<updated>2016-06-19T14:10:28Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{MC-Basic&lt;br /&gt;
|SHORT FORM= Torque&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
Torque &amp;lt;''axis''&amp;gt; &amp;lt;''Torque Value''&amp;gt; {TorqueChangeRatio=&amp;lt;''value''&amp;gt;} {TorqueChnageRatioMax=&amp;lt;''value''&amp;gt;} {StartType = Generator-Completed, Immediate, Super-Immediate}&lt;br /&gt;
|AVAILABILITY= Since Version 4.9.0&lt;br /&gt;
|DESCRIPTION= &lt;br /&gt;
&lt;br /&gt;
*If executed in a mode different than TORQUEMODE a note will be thrown, but the command will be executed as usual&lt;br /&gt;
&lt;br /&gt;
*Interpolates torque command ([[MC-Basic:axis.TORQUECOMMAND|TCMD]]) value from its initial value to the given torque value. The interpolation is done using the value of '''min([[MC-Basic:axis.TORQUECHANGERATIO|TorqueChangeRatio]],[[MC-Basic:axis.TORQUECHANGERATIOMAX|TorqueChangeRatioMax]])''' value as a rate of TCMD value change. No additional smoothing is done.&lt;br /&gt;
&lt;br /&gt;
*The torque interpolation is done using same mechanisms as motion interpolation. Depending on the value of &amp;lt;''axis''&amp;gt;.StartType the interpolation will start after the previous torque command was given or immediately (same rules as move command).The value of inpos for the starttype will be ignored and GCOMP will be used instead.&lt;br /&gt;
&lt;br /&gt;
*During execution the value of isMoving will be nonzero. Values of axis PCMD, VCMD, ACCELCOMMAND are not affected.&lt;br /&gt;
 &lt;br /&gt;
|TYPE=&lt;br /&gt;
&amp;lt;''Torque Value''&amp;gt; - double&lt;br /&gt;
|RANGE=&lt;br /&gt;
|UNITS=&lt;br /&gt;
|DEFAULT=&lt;br /&gt;
|SCOPE=&lt;br /&gt;
|LIMITATIONS= &lt;br /&gt;
|EXAMPLE= Torque Ax1 10.1 ''StartType=Immediate''&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
* [[MC-Basic:axis.OPMODE|OPMODE]]&lt;br /&gt;
* [[MC-Basic:axis.TORQUECHANGERATIO|TORQUECHANGERATIO]]&lt;br /&gt;
* [[MC-Basic:axis.TORQUECHANGERATIOMAX|TORQUECHANGERATIOMAX]]&lt;br /&gt;
* [[MC-Basic:axis.SUMTORQUE|SUMTORQUE]]&lt;br /&gt;
&lt;br /&gt;
* [[MC-Basic:axis.TORQUECOMMAND|TORQUECOMMAND]]&lt;br /&gt;
* [[MC-Basic:axis.COUNTTORQUECOMMAND|COUNTTORQUECOMMAND]]&lt;br /&gt;
&lt;br /&gt;
* [[MC-Basic:axis.TORQUEADDCOMMAND|TORQUEADDCOMMAND]]&lt;br /&gt;
* [[MC-Basic:axis.COUNTTORQUEADDITIVECOMMAND|COUNTTORQUEADDITIVECOMMAND]]&lt;br /&gt;
&lt;br /&gt;
* [[MC-Basic:axis.TORQUEFEEDBACK|TORQUEFEEDBACK]]&lt;br /&gt;
* [[MC-Basic:axis.COUNTTORQUEFEEDBACK|COUNTTORQUEFEEDBACK]]&lt;br /&gt;
&lt;br /&gt;
* [[MC-Basic:axis.TORQUEDRIVECOMMAND|TORQUEDRIVECOMMAND]]&lt;br /&gt;
* [[MC-Basic:axis.COUNTTORQUEDRIVECOMMAND|COUNTTORQUEDRIVECOMMAND]]&lt;br /&gt;
&lt;br /&gt;
* [[OperationalModes| Operational Modes]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
* ''[[AXY:MC_Operational_Modes | MC Operational Modes]]''&lt;br /&gt;
* ''[[AXY:Operational_Modes | Operational Modes]]''&lt;br /&gt;
}}&lt;br /&gt;
[[Category:OperationalModes]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125799</id>
		<title>Category:EtherCAT:EC SETUP</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125799"/>
				<updated>2016-02-28T12:20:56Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Category&lt;br /&gt;
|description=How to Set up EtherCAT.&lt;br /&gt;
|frontpage=[[EtherCAT]]&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
Before starting to work with the softMC, you must setup the EtherCAT master to work with the slaves.&amp;lt;br/&amp;gt;&lt;br /&gt;
You must configure the axes in the system in a certain manner, then invoke certain functions and subroutines in an orderly manner, and make sure no errors occur.&lt;br /&gt;
&lt;br /&gt;
A CONFIG.PRG and a program file EC_SETUP.PRG exist in the repository, and demonstrate the following process.&lt;br /&gt;
&lt;br /&gt;
CONFIG.PRG allocates an array of generic axes by the name Axes[], and sets all the existing axes in the system into this array.&amp;lt;br/&amp;gt;&lt;br /&gt;
{{Note| Since verison 0.4.15.3rc6 the global axis array systemAxis[] is introduced, and the array Axes[] is made redundant, therefore it is removed from CONFIG.PRG }}&lt;br /&gt;
EC_SETUP.PRG and AX_SETUP.PRG use this array to setup the system automatically.&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
It is critical to maintain the demonstrated order of the EtherCAT setup.&amp;lt;br/&amp;gt;Any change in the given example may result in undefined behavior!}}&lt;br /&gt;
&lt;br /&gt;
==EC_SETUP.PRG==&lt;br /&gt;
EC_SETUP.PRG is a generic script. Its purpose is to configure the EtherCAT master and slaves before they are started, start the master, and eventually run additional actions to complete the EtherCAT startup procedure.&lt;br /&gt;
&lt;br /&gt;
EC_SETUP.PRG is written in a manner that easily allows embedding code to configure specific motion drives and IO modules.&lt;br /&gt;
&lt;br /&gt;
This article details the main steps that occur upon EtherCAT startup as they are executed by EC_SETUP.PRG.&lt;br /&gt;
&lt;br /&gt;
==Drive Address==&lt;br /&gt;
Each EtherCAT slave has an address. Currently this address is determined strictly according to the slave location in the&lt;br /&gt;
[[:File:Axystems;EC_master_slave_position_topology.PNG|physical topology]] of the system; that is, the first slave attached to the MC is assigned drive address 1, the second slave in the chain gets slave address 2, and so on. &lt;br /&gt;
&lt;br /&gt;
An EtherCAT slave can be a motion drive, an IO module or a Gateway.&lt;br /&gt;
&lt;br /&gt;
==PRE-OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Before the master is started all the slaves are in PRE-OP mode. In this stage the master is created and the system gathers information from the slaves in order to create data structures that are used by the master to set up the EtherCAT communication.&lt;br /&gt;
&lt;br /&gt;
First, differentiate between '''motion drives''' and '''IO modules'''. For each slave query the slave's Vendor ID and Product Code.&lt;br /&gt;
This data can later be used to identify specific products and create specific configuration for them, as in the [[EtherCAT:EC_INSTALL_STX_CDHD|CDHD Configuration example]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	numOfSlaves = EC_ETHERCAT_INIT&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Look for an unknown generic DS402 motion drive. If found, remap its PDOs to the required minimum.&amp;lt;br/&amp;gt;&lt;br /&gt;
You may update the following code by replacing the define GENERIC_DS402_DRIVE_VENDOR with your device's vendor ID, by doing so remapping its PDO's to the required minimum to create sync position motion:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	for drive_addr = 1 to numOfSlaves&lt;br /&gt;
		if ETSLAVES[drive_addr]-&amp;gt;et_slavetype = ECAT_MOTIONSLAVE then&lt;br /&gt;
			if EC_SLAVES_INFO[drive_addr]-&amp;gt;vendor_id = GENERIC_DS402_DRIVE_VENDOR then  '  replace with your product's vendor ID&lt;br /&gt;
				call EC_REMAP_MINIMUM_PDOS(drive_addr)&lt;br /&gt;
			end if&lt;br /&gt;
		end if&lt;br /&gt;
	next&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Check the EtherCAT Topology for Wiring Errors===&lt;br /&gt;
EtherCAT topology is sensitive to the direction of the wiring. Each EtherCAT slave has an INPUT connector and an OUTPUT connector.&amp;lt;br/&amp;gt;&lt;br /&gt;
The cable that &amp;quot;starts&amp;quot; from the EtherCAT master's OUTPUT must be connected to the INPUT of the first EtherCAT slave. A second cable will &amp;quot;exit&amp;quot; from the OUTPUT of the first slave and get connected to the INPUT of the second slave, etc...&amp;lt;br/&amp;gt;&lt;br /&gt;
'Miswiring' on most occasions means that somewhere in the topology the EtherCAT cable wiring got confused between the INPUT and the OUTPUT connectors.&amp;lt;br/&amp;gt;&lt;br /&gt;
This situation results UNDEFINED behavior, even up to making the wrong motor move, which is a safety issue.&lt;br /&gt;
{{Note/Important|If a miswiring is detected, an error will be thrown and EC_SETUP.PRG will stop running}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	retVal = CHECK_TOPOLOGY&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create the EtherCAT Master.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_CREATE_MASTER&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set Motion Cycle Time: 4000, 2000, 1000, 500 or 250 [us]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_SET_BUS_CYCLETIME(4000)  '  for a cycle time of 500/250[us], add to FWCONFIG: hpetfreq = 2000&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
From here on EC_SETUP.PRG uses the gathered information to configure the slaves. A 'For Loop' goes over the slaves and tries to match&lt;br /&gt;
them to already known products (such as the CDHD). When found, product specific functions are invoked to create data structures in the master that elaborate the PDO mapping of the slaves, be it a motion drive or an IO module. This is where you can add your own code to configure your own EtherCAT slave. Just add another case to match your Vendor ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
You may use the already prepared GENERIC_DS402_DRIVE_VENDOR case.&amp;lt;br/&amp;gt;&lt;br /&gt;
Replace the define GENERIC_DS402_DRIVE_VENDOR with your device's vendor ID, and GENERIC_DS402_DRIVE_PRODUCT_ID with the device's product code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
      Case GENERIC_DS402_DRIVE_VENDOR  '  replace with your vendor id&lt;br /&gt;
&lt;br /&gt;
        if EC_SLAVES_INFO[drive_addr]-&amp;gt;product_code = GENERIC_DS402_DRIVE_PRODUCT_ID then  '  replace with your product id&lt;br /&gt;
&lt;br /&gt;
          call EC_INSTALL_GENERIC_DRIVE(drive_addr, Counts_Per_Revolution)  '  Counts Per motor Revolution&lt;br /&gt;
          num_Of_Motion_Drives = num_Of_Motion_Drives + 1&lt;br /&gt;
&lt;br /&gt;
        end if&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If a Servotronix (STX) CDHD servo motion drive is found, the function [[EtherCAT:EC_INSTALL_STX_CDHD|EC_INSTALL_STX_CDHD]] is invoked. This function sets certain parameters in the drive, creates the PDO map of the CDHD, and queries the drive's PNUM and PDEN to allow calculation of the [[MC-Basic:axis.POSITIONFACTOR|Position Factor]].&lt;br /&gt;
&lt;br /&gt;
For a generic drive, a minimum PDO mapping and default values are used. &lt;br /&gt;
&lt;br /&gt;
The user can add his own code to [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]] to perform any specific configuration that must take place while the slaves are in PREOP mode.&lt;br /&gt;
&lt;br /&gt;
After the slave configuration is done the master is started:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' Create PDOs mapping, set bus cycle time, sync clocks between the master and the slaves,&lt;br /&gt;
	' raise slaves to OP-Mode and sets master's opmode to operational&lt;br /&gt;
	call EC_STARTMASTER  ' Syncs clocks between the master and the slaves, and sets master's opmode to operational&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The master attempts to raise all the slaves to OP Mode. If it fails, the procedure is stopped and an error is issued.&lt;br /&gt;
If it is successful, EtherCAT communication is now online and EC_SETUP.PRG starts the second stage of configuration.&lt;br /&gt;
&lt;br /&gt;
==OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Again, a For Loop goes over all the slaves. When a motion drive is encountered, EC_SETUP.PRG attaches its drive address to an axis and&lt;br /&gt;
attempts to clear its faults.&lt;br /&gt;
Again, the user can add his own code to [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]] and [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]] to perform any specific configuration that must take place while the slaves are in &amp;quot;SAFEOP&amp;quot; or &amp;quot;OP&amp;quot; mode.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' SAFEOP state configuration - Add code to EC_USER_SAFEOP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_SAFEOP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' OP state configuration - Add code to EC_USER_OP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_OP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' Assign ECAT bus ID and slave address to an axis&lt;br /&gt;
	systemAxis(Axis_Attached_To_Drive).busnumber = ECAT_BUSID&lt;br /&gt;
	systemAxis(Axis_Attached_To_Drive).dadd = drive_addr&lt;br /&gt;
&lt;br /&gt;
	' Attempt to clear faults in the drives&lt;br /&gt;
	Try&lt;br /&gt;
&lt;br /&gt;
		call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	Catch Else&lt;br /&gt;
&lt;br /&gt;
		' if clear faults failed due to PLL Sync Error, wait a little longer and retry&lt;br /&gt;
		if EC_SDO_READ(drive_addr, 0x603f, 0) = 0x7386 then&lt;br /&gt;
			printu &amp;quot;PLL Error in drive #. Sleeping 5 seconds and retrying to clear fault&amp;quot;;drive_addr&lt;br /&gt;
			sleep 5000&lt;br /&gt;
			call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
		end if&lt;br /&gt;
&lt;br /&gt;
	End Try&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
All the motion drives are set to Synchronous Position Mode:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' Set drives to sync position mode&lt;br /&gt;
	if EC_IS_PDO(Axes[Axis_Attached_To_Drive].dadd, 0x6060, 0) then&lt;br /&gt;
		call EC_PDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8)&lt;br /&gt;
	else&lt;br /&gt;
		call EC_SDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8, 8)&lt;br /&gt;
	end if&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
* [[EtherCAT:EC ETHERCAT INIT|EC_ETHERCAT_INIT]]&lt;br /&gt;
* [[EtherCAT:EC REMAP MINIMUM PDOS|EC_REMAP_MINIMUM_PDOS]]&lt;br /&gt;
* [[EtherCAT:EC CREATE MASTER|EC_CREATE_MASTER]]&lt;br /&gt;
* [[EtherCAT:EC SET BUS CYCLETIME|EC_SET_BUS_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC GET BUS CYCLETIME|EC_GET_BUS_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC STARTMASTER|EC_STARTMASTER]]&lt;br /&gt;
* [[EtherCAT:EC CLEAR FAULTS|EC_CLEAR_FAULTS]]&lt;br /&gt;
* [[EtherCAT:EC SDO READ|EC_SDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC SDO WRITE|EC_SDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC PDO READ|EC_PDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC PDO WRITE|EC_PDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC IS PDO|EC_IS_PDO]]&lt;br /&gt;
* [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
[[Category:EtherCAT]]&lt;br /&gt;
[[Category:Control:Offline]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125798</id>
		<title>Category:EtherCAT:EC SETUP</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125798"/>
				<updated>2016-02-28T12:19:41Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Category&lt;br /&gt;
|description=How to Set up EtherCAT.&lt;br /&gt;
|frontpage=[[EtherCAT]]&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
Before starting to work with the softMC, you must setup the EtherCAT master to work with the slaves.&amp;lt;br/&amp;gt;&lt;br /&gt;
You must configure the axes in the system in a certain manner, then invoke certain functions and subroutines in an orderly manner, and make sure no errors occur.&lt;br /&gt;
&lt;br /&gt;
A CONFIG.PRG and a program file EC_SETUP.PRG exist in the repository, and demonstrate the following process.&lt;br /&gt;
&lt;br /&gt;
CONFIG.PRG allocates an array of generic axes by the name Axes[], and sets all the existing axes in the system into this array.&amp;lt;br/&amp;gt;&lt;br /&gt;
{{Note| Since verison 0.4.15.3rc6 the global axis array systemAxis[] is introduced, and the array Axes[] is made redundant, therefore it is removed from CONFIG.PRG }}&lt;br /&gt;
EC_SETUP.PRG and AX_SETUP.PRG use this array to setup the system automatically.&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
It is critical to maintain the demonstrated order of the EtherCAT setup.&amp;lt;br/&amp;gt;Any change in the given example may result in undefined behavior!}}&lt;br /&gt;
&lt;br /&gt;
==EC_SETUP.PRG==&lt;br /&gt;
EC_SETUP.PRG is a generic script. Its purpose is to configure the EtherCAT master and slaves before they are started, start the master, and eventually run additional actions to complete the EtherCAT startup procedure.&lt;br /&gt;
&lt;br /&gt;
EC_SETUP.PRG is written in a manner that easily allows embedding code to configure specific motion drives and IO modules.&lt;br /&gt;
&lt;br /&gt;
This article details the main steps that occur upon EtherCAT startup as they are executed by EC_SETUP.PRG.&lt;br /&gt;
&lt;br /&gt;
==Drive Address==&lt;br /&gt;
Each EtherCAT slave has an address. Currently this address is determined strictly according to the slave location in the&lt;br /&gt;
[[:File:Axystems;EC_master_slave_position_topology.PNG|physical topology]] of the system; that is, the first slave attached to the MC is assigned drive address 1, the second slave in the chain gets slave address 2, and so on. &lt;br /&gt;
&lt;br /&gt;
An EtherCAT slave can be a motion drive, an IO module or a Gateway.&lt;br /&gt;
&lt;br /&gt;
==PRE-OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Before the master is started all the slaves are in PRE-OP mode. In this stage the master is created and the system gathers information from the slaves in order to create data structures that are used by the master to set up the EtherCAT communication.&lt;br /&gt;
&lt;br /&gt;
First, differentiate between '''motion drives''' and '''IO modules'''. For each slave query the slave's Vendor ID and Product Code.&lt;br /&gt;
This data can later be used to identify specific products and create specific configuration for them, as in the [[EtherCAT:EC_INSTALL_STX_CDHD|CDHD Configuration example]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	numOfSlaves = EC_ETHERCAT_INIT&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Look for an unknown generic DS402 motion drive. If found, remap its PDOs to the required minimum.&amp;lt;br/&amp;gt;&lt;br /&gt;
You may update the following code by replacing the define GENERIC_DS402_DRIVE_VENDOR with your device's vendor ID, by doing so remapping its PDO's to the required minimum to create sync position motion:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	for drive_addr = 1 to numOfSlaves&lt;br /&gt;
		if ETSLAVES[drive_addr]-&amp;gt;et_slavetype = ECAT_MOTIONSLAVE then&lt;br /&gt;
			if EC_SLAVES_INFO[drive_addr]-&amp;gt;vendor_id = GENERIC_DS402_DRIVE_VENDOR then  '  replace with your product's vendor ID&lt;br /&gt;
				call EC_REMAP_MINIMUM_PDOS(drive_addr)&lt;br /&gt;
			end if&lt;br /&gt;
		end if&lt;br /&gt;
	next&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Check the EtherCAT Topology for Wiring Errors===&lt;br /&gt;
EtherCAT topology is sensitive to the direction of the wiring. Each EtherCAT slave has an INPUT connector and an OUTPUT connector.&amp;lt;br/&amp;gt;&lt;br /&gt;
The cable that &amp;quot;starts&amp;quot; from the EtherCAT master's OUTPUT must be connected to the INPUT of the first EtherCAT slave. A second cable will &amp;quot;exit&amp;quot; from the OUTPUT of the first slave and get connected to the INPUT of the second slave, etc...&amp;lt;br/&amp;gt;&lt;br /&gt;
'Miswiring' on most occasions means that somewhere in the topology the EtherCAT cable wiring got confused between the INPUT and the OUTPUT connectors.&amp;lt;br/&amp;gt;&lt;br /&gt;
This situation results UNDEFINED behavior, even up to making the wrong motor move, which is a safety issue.&lt;br /&gt;
{{Note/Important|If a miswiring is detected, an error will be thrown and EC_SETUP.PRG will stop running}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	retVal = CHECK_TOPOLOGY&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create the EtherCAT Master.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_CREATE_MASTER&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set Motion Cycle Time: 4000, 2000, 1000, 500 or 250 [us]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_SET_BUS_CYCLETIME(4000)  '  for a cycle time of 500/250[us], add to FWCONFIG: hpetfreq = 2000&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
From here on EC_SETUP.PRG uses the gathered information to configure the slaves. A 'For Loop' goes over the slaves and tries to match&lt;br /&gt;
them to already known products (such as the CDHD). When found, product specific functions are invoked to create data structures in the master that elaborate the PDO mapping of the slaves, be it a motion drive or an IO module. This is where you can add your own code to configure your own EtherCAT slave. Just add another case to match your Vendor ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
You may use the already prepared GENERIC_DS402_DRIVE_VENDOR case.&amp;lt;br/&amp;gt;&lt;br /&gt;
Replace the define GENERIC_DS402_DRIVE_VENDOR with your device's vendor ID, and GENERIC_DS402_DRIVE_PRODUCT_ID with the device's product code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
      Case GENERIC_DS402_DRIVE_VENDOR  '  replace with your vendor id&lt;br /&gt;
&lt;br /&gt;
        if EC_SLAVES_INFO[drive_addr]-&amp;gt;product_code = GENERIC_DS402_DRIVE_PRODUCT_ID then  '  replace with your product id&lt;br /&gt;
&lt;br /&gt;
          call EC_INSTALL_GENERIC_DRIVE(drive_addr, Counts_Per_Revolution)  '  Counts Per motor Revolution&lt;br /&gt;
          num_Of_Motion_Drives = num_Of_Motion_Drives + 1&lt;br /&gt;
&lt;br /&gt;
        end if&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If a Servotronix (STX) CDHD servo motion drive is found, the function [[EtherCAT:EC_INSTALL_STX_CDHD|EC_INSTALL_STX_CDHD]] is invoked. This function sets certain parameters in the drive, creates the PDO map of the CDHD, and queries the drive's PNUM and PDEN to allow calculation of the [[MC-Basic:axis.POSITIONFACTOR|Position Factor]].&lt;br /&gt;
&lt;br /&gt;
For a generic drive, a minimum PDO mapping and default values are used. &lt;br /&gt;
&lt;br /&gt;
The user can add his own code to [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]] to perform any specific configuration that must take place while the slaves are in PREOP mode.&lt;br /&gt;
&lt;br /&gt;
After the slave configuration is done the master is started:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' Create PDOs mapping, set bus cycle time, sync clocks between the master and the slaves,&lt;br /&gt;
	' raise slaves to OP-Mode and sets master's opmode to operational&lt;br /&gt;
	call EC_STARTMASTER  ' Syncs clocks between the master and the slaves, and sets master's opmode to operational&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The master attempts to raise all the slaves to OP Mode. If it fails, the procedure is stopped and an error is issued.&lt;br /&gt;
If it is successful, EtherCAT communication is now online and EC_SETUP.PRG starts the second stage of configuration.&lt;br /&gt;
&lt;br /&gt;
==OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Again, a For Loop goes over all the slaves. When a motion drive is encountered, EC_SETUP.PRG attaches its drive address to an axis and&lt;br /&gt;
attempts to clear its faults.&lt;br /&gt;
Again, the user can add his own code to [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]] and [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]] to perform any specific configuration that must take place while the slaves are in &amp;quot;SAFEOP&amp;quot; or &amp;quot;OP&amp;quot; mode.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' SAFEOP state configuration - Add code to EC_USER_SAFEOP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_SAFEOP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' OP state configuration - Add code to EC_USER_OP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_OP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' Assign ECAT bus ID and slave address to an axis&lt;br /&gt;
	systemAxis(Axis_Attached_To_Drive).busnumber = ECAT_BUSID&lt;br /&gt;
	systemAxis(Axis_Attached_To_Drive).dadd = drive_addr&lt;br /&gt;
&lt;br /&gt;
	' Attempt to clear faults in the drives&lt;br /&gt;
	Try&lt;br /&gt;
&lt;br /&gt;
		call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	Catch Else&lt;br /&gt;
&lt;br /&gt;
		' if clear faults failed due to PLL Sync Error, wait a little longer and retry&lt;br /&gt;
		if EC_SDO_READ(drive_addr, 0x603f, 0) = 0x7386 then&lt;br /&gt;
			printu &amp;quot;PLL Error in drive #. Sleeping 5 seconds and retrying to clear fault&amp;quot;;drive_addr&lt;br /&gt;
			sleep 5000&lt;br /&gt;
			call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
		end if&lt;br /&gt;
&lt;br /&gt;
	End Try&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
All the motion drives are set to Synchronous Position Mode:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' Set drives to sync position mode&lt;br /&gt;
	if EC_IS_PDO(Axes[Axis_Attached_To_Drive].dadd, 0x6060, 0) then&lt;br /&gt;
		call EC_PDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8)&lt;br /&gt;
	else&lt;br /&gt;
		call EC_SDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8, 8)&lt;br /&gt;
	end if&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
* [[EtherCAT:EC ETHERCAT INIT|EC_ETHERCAT_INIT]]&lt;br /&gt;
* [[EtherCAT:EC REMAP MINIMUM PDOS|EC_REMAP_MINIMUM_PDOS]]&lt;br /&gt;
* [[EtherCAT:EC CREATE MASTER|EC_CREATE_MASTER]]&lt;br /&gt;
* [[EtherCAT:EC SET BUS CYCLETIME|EC_SET_BUS_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC GET BUS CYCLETIME|EC_SET_BUS_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC STARTMASTER|EC_STARTMASTER]]&lt;br /&gt;
* [[EtherCAT:EC CLEAR FAULTS|EC_CLEAR_FAULTS]]&lt;br /&gt;
* [[EtherCAT:EC SDO READ|EC_SDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC SDO WRITE|EC_SDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC PDO READ|EC_PDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC PDO WRITE|EC_PDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC IS PDO|EC_IS_PDO]]&lt;br /&gt;
* [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
[[Category:EtherCAT]]&lt;br /&gt;
[[Category:Control:Offline]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125797</id>
		<title>Category:EtherCAT:EC SETUP</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125797"/>
				<updated>2016-02-28T12:17:37Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Category&lt;br /&gt;
|description=How to Set up EtherCAT.&lt;br /&gt;
|frontpage=[[EtherCAT]]&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
Before starting to work with the softMC, you must setup the EtherCAT master to work with the slaves.&amp;lt;br/&amp;gt;&lt;br /&gt;
You must configure the axes in the system in a certain manner, then invoke certain functions and subroutines in an orderly manner, and make sure no errors occur.&lt;br /&gt;
&lt;br /&gt;
A CONFIG.PRG and a program file EC_SETUP.PRG exist in the repository, and demonstrate the following process.&lt;br /&gt;
&lt;br /&gt;
CONFIG.PRG allocates an array of generic axes by the name Axes[], and sets all the existing axes in the system into this array.&amp;lt;br/&amp;gt;&lt;br /&gt;
{{Note| Since verison 0.4.15.3rc6 the global axis array systemAxis[] is introduced, and the array Axes[] is made redundant, therefore it is removed from CONFIG.PRG }}&lt;br /&gt;
EC_SETUP.PRG and AX_SETUP.PRG use this array to setup the system automatically.&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
It is critical to maintain the demonstrated order of the EtherCAT setup.&amp;lt;br/&amp;gt;Any change in the given example may result in undefined behavior!}}&lt;br /&gt;
&lt;br /&gt;
==EC_SETUP.PRG==&lt;br /&gt;
EC_SETUP.PRG is a generic script. Its purpose is to configure the EtherCAT master and slaves before they are started, start the master, and eventually run additional actions to complete the EtherCAT startup procedure.&lt;br /&gt;
&lt;br /&gt;
EC_SETUP.PRG is written in a manner that easily allows embedding code to configure specific motion drives and IO modules.&lt;br /&gt;
&lt;br /&gt;
This article details the main steps that occur upon EtherCAT startup as they are executed by EC_SETUP.PRG.&lt;br /&gt;
&lt;br /&gt;
==Drive Address==&lt;br /&gt;
Each EtherCAT slave has an address. Currently this address is determined strictly according to the slave location in the&lt;br /&gt;
[[:File:Axystems;EC_master_slave_position_topology.PNG|physical topology]] of the system; that is, the first slave attached to the MC is assigned drive address 1, the second slave in the chain gets slave address 2, and so on. &lt;br /&gt;
&lt;br /&gt;
An EtherCAT slave can be a motion drive, an IO module or a Gateway.&lt;br /&gt;
&lt;br /&gt;
==PRE-OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Before the master is started all the slaves are in PRE-OP mode. In this stage the master is created and the system gathers information from the slaves in order to create data structures that are used by the master to set up the EtherCAT communication.&lt;br /&gt;
&lt;br /&gt;
First, differentiate between '''motion drives''' and '''IO modules'''. For each slave query the slave's Vendor ID and Product Code.&lt;br /&gt;
This data can later be used to identify specific products and create specific configuration for them, as in the [[EtherCAT:EC_INSTALL_STX_CDHD|CDHD Configuration example]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	numOfSlaves = EC_ETHERCAT_INIT&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Look for an unknown generic DS402 motion drive. If found, remap its PDOs to the required minimum.&amp;lt;br/&amp;gt;&lt;br /&gt;
You may update the following code by replacing the define GENERIC_DS402_DRIVE_VENDOR with your device's vendor ID, by doing so remapping its PDO's to the required minimum to create sync position motion:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	for drive_addr = 1 to numOfSlaves&lt;br /&gt;
		if ETSLAVES[drive_addr]-&amp;gt;et_slavetype = ECAT_MOTIONSLAVE then&lt;br /&gt;
			if EC_SLAVES_INFO[drive_addr]-&amp;gt;vendor_id = GENERIC_DS402_DRIVE_VENDOR then  '  replace with your product's vendor ID&lt;br /&gt;
				call EC_REMAP_MINIMUM_PDOS(drive_addr)&lt;br /&gt;
			end if&lt;br /&gt;
		end if&lt;br /&gt;
	next&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Check the EtherCAT Topology for Wiring Errors===&lt;br /&gt;
EtherCAT topology is sensitive to the direction of the wiring. Each EtherCAT slave has an INPUT connector and an OUTPUT connector.&amp;lt;br/&amp;gt;&lt;br /&gt;
The cable that &amp;quot;starts&amp;quot; from the EtherCAT master's OUTPUT must be connected to the INPUT of the first EtherCAT slave. A second cable will &amp;quot;exit&amp;quot; from the OUTPUT of the first slave and get connected to the INPUT of the second slave, etc...&amp;lt;br/&amp;gt;&lt;br /&gt;
'Miswiring' on most occasions means that somewhere in the topology the EtherCAT cable wiring got confused between the INPUT and the OUTPUT connectors.&amp;lt;br/&amp;gt;&lt;br /&gt;
This situation results UNDEFINED behavior, even up to making the wrong motor move, which is a safety issue.&lt;br /&gt;
{{Note/Important|If a miswiring is detected, an error will be thrown and EC_SETUP.PRG will stop running}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	retVal = CHECK_TOPOLOGY&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create the EtherCAT Master.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_CREATE_MASTER&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set Motion Cycle Time: 4000, 2000, 1000, 500 or 250 [us]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_SET_BUS_CYCLETIME(4000)  '  for a cycle time of 500/250[us], add to FWCONFIG: hpetfreq = 2000&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
From here on EC_SETUP.PRG uses the gathered information to configure the slaves. A 'For Loop' goes over the slaves and tries to match&lt;br /&gt;
them to already known products (such as the CDHD). When found, product specific functions are invoked to create data structures in the master that elaborate the PDO mapping of the slaves, be it a motion drive or an IO module. This is where you can add your own code to configure your own EtherCAT slave. Just add another case to match your Vendor ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
You may use the already prepared GENERIC_DS402_DRIVE_VENDOR case.&amp;lt;br/&amp;gt;&lt;br /&gt;
Replace the define GENERIC_DS402_DRIVE_VENDOR with your device's vendor ID, and GENERIC_DS402_DRIVE_PRODUCT_ID with the device's product code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
      Case GENERIC_DS402_DRIVE_VENDOR  '  replace with your vendor id&lt;br /&gt;
&lt;br /&gt;
        if EC_SLAVES_INFO[drive_addr]-&amp;gt;product_code = GENERIC_DS402_DRIVE_PRODUCT_ID then  '  replace with your product id&lt;br /&gt;
&lt;br /&gt;
          call EC_INSTALL_GENERIC_DRIVE(drive_addr, Counts_Per_Revolution)  '  Counts Per motor Revolution&lt;br /&gt;
          num_Of_Motion_Drives = num_Of_Motion_Drives + 1&lt;br /&gt;
&lt;br /&gt;
        end if&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If a Servotronix (STX) CDHD servo motion drive is found, the function [[EtherCAT:EC_INSTALL_STX_CDHD|EC_INSTALL_STX_CDHD]] is invoked. This function sets certain parameters in the drive, creates the PDO map of the CDHD, and queries the drive's PNUM and PDEN to allow calculation of the [[MC-Basic:axis.POSITIONFACTOR|Position Factor]].&lt;br /&gt;
&lt;br /&gt;
For a generic drive, a minimum PDO mapping and default values are used. &lt;br /&gt;
&lt;br /&gt;
The user can add his own code to [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]] to perform any specific configuration that must take place while the slaves are in PREOP mode.&lt;br /&gt;
&lt;br /&gt;
After the slave configuration is done the master is started:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' Create PDOs mapping, set bus cycle time, sync clocks between the master and the slaves,&lt;br /&gt;
	' raise slaves to OP-Mode and sets master's opmode to operational&lt;br /&gt;
	call EC_STARTMASTER  ' Syncs clocks between the master and the slaves, and sets master's opmode to operational&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The master attempts to raise all the slaves to OP Mode. If it fails, the procedure is stopped and an error is issued.&lt;br /&gt;
If it is successful, EtherCAT communication is now online and EC_SETUP.PRG starts the second stage of configuration.&lt;br /&gt;
&lt;br /&gt;
==OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Again, a For Loop goes over all the slaves. When a motion drive is encountered, EC_SETUP.PRG attaches its drive address to an axis and&lt;br /&gt;
attempts to clear its faults.&lt;br /&gt;
Again, the user can add his own code to [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]] and [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]] to perform any specific configuration that must take place while the slaves are in &amp;quot;SAFEOP&amp;quot; or &amp;quot;OP&amp;quot; mode.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' SAFEOP state configuration - Add code to EC_USER_SAFEOP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_SAFEOP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' OP state configuration - Add code to EC_USER_OP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_OP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' Assign slave address to an axis&lt;br /&gt;
	Axes[Axis_Attached_To_Drive].dadd = drive_addr&lt;br /&gt;
&lt;br /&gt;
	' Attempt to clear faults in the drives&lt;br /&gt;
	Try&lt;br /&gt;
&lt;br /&gt;
		call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	Catch Else&lt;br /&gt;
&lt;br /&gt;
		' if clear faults failed due to PLL Sync Error, wait a little longer and retry&lt;br /&gt;
		if EC_SDO_READ(drive_addr, 0x603f, 0) = 0x7386 then&lt;br /&gt;
			printu &amp;quot;PLL Error in drive #. Sleeping 5 seconds and retrying to clear fault&amp;quot;;drive_addr&lt;br /&gt;
			sleep 5000&lt;br /&gt;
			call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
		end if&lt;br /&gt;
&lt;br /&gt;
	End Try&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
All the motion drives are set to Synchronous Position Mode:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' Set drives to sync position mode&lt;br /&gt;
	if EC_IS_PDO(Axes[Axis_Attached_To_Drive].dadd, 0x6060, 0) then&lt;br /&gt;
		call EC_PDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8)&lt;br /&gt;
	else&lt;br /&gt;
		call EC_SDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8, 8)&lt;br /&gt;
	end if&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
* [[EtherCAT:EC ETHERCAT INIT|EC_ETHERCAT_INIT]]&lt;br /&gt;
* [[EtherCAT:EC REMAP MINIMUM PDOS|EC_REMAP_MINIMUM_PDOS]]&lt;br /&gt;
* [[EtherCAT:EC CREATE MASTER|EC_CREATE_MASTER]]&lt;br /&gt;
* [[EtherCAT:EC SET BUS CYCLETIME|EC_SET_BUS_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC GET BUS CYCLETIME|EC_SET_BUS_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC STARTMASTER|EC_STARTMASTER]]&lt;br /&gt;
* [[EtherCAT:EC CLEAR FAULTS|EC_CLEAR_FAULTS]]&lt;br /&gt;
* [[EtherCAT:EC SDO READ|EC_SDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC SDO WRITE|EC_SDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC PDO READ|EC_PDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC PDO WRITE|EC_PDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC IS PDO|EC_IS_PDO]]&lt;br /&gt;
* [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
[[Category:EtherCAT]]&lt;br /&gt;
[[Category:Control:Offline]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125796</id>
		<title>Category:EtherCAT:EC SETUP</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125796"/>
				<updated>2016-02-28T12:15:19Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Category&lt;br /&gt;
|description=How to Set up EtherCAT.&lt;br /&gt;
|frontpage=[[EtherCAT]]&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
Before starting to work with the softMC, you must setup the EtherCAT master to work with the slaves.&amp;lt;br/&amp;gt;&lt;br /&gt;
You must configure the axes in the system in a certain manner, then invoke certain functions and subroutines in an orderly manner, and make sure no errors occur.&lt;br /&gt;
&lt;br /&gt;
A CONFIG.PRG and a program file EC_SETUP.PRG exist in the repository, and demonstrate the following process.&lt;br /&gt;
&lt;br /&gt;
CONFIG.PRG allocates an array of generic axes by the name Axes[], and sets all the existing axes in the system into this array.&amp;lt;br/&amp;gt;&lt;br /&gt;
{{Note| Since verison 0.4.15.3rc6 the global axis array systemAxis[] is introduced, and the array Axes[] is made redundant, therefore it is removed from CONFIG.PRG }}&lt;br /&gt;
EC_SETUP.PRG and AX_SETUP.PRG use this array to setup the system automatically.&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
It is critical to maintain the demonstrated order of the EtherCAT setup.&amp;lt;br/&amp;gt;Any change in the given example may result in undefined behavior!}}&lt;br /&gt;
&lt;br /&gt;
==EC_SETUP.PRG==&lt;br /&gt;
EC_SETUP.PRG is a generic script. Its purpose is to configure the EtherCAT master and slaves before they are started, start the master, and eventually run additional actions to complete the EtherCAT startup procedure.&lt;br /&gt;
&lt;br /&gt;
EC_SETUP.PRG is written in a manner that easily allows embedding code to configure specific motion drives and IO modules.&lt;br /&gt;
&lt;br /&gt;
This article details the main steps that occur upon EtherCAT startup as they are executed by EC_SETUP.PRG.&lt;br /&gt;
&lt;br /&gt;
==Drive Address==&lt;br /&gt;
Each EtherCAT slave has an address. Currently this address is determined strictly according to the slave location in the&lt;br /&gt;
[[:File:Axystems;EC_master_slave_position_topology.PNG|physical topology]] of the system; that is, the first slave attached to the MC is assigned drive address 1, the second slave in the chain gets slave address 2, and so on. &lt;br /&gt;
&lt;br /&gt;
An EtherCAT slave can be a motion drive, an IO module or a Gateway.&lt;br /&gt;
&lt;br /&gt;
==PRE-OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Before the master is started all the slaves are in PRE-OP mode. In this stage the master is created and the system gathers information from the slaves in order to create data structures that are used by the master to set up the EtherCAT communication.&lt;br /&gt;
&lt;br /&gt;
First, differentiate between '''motion drives''' and '''IO modules'''. For each slave query the slave's Vendor ID and Product Code.&lt;br /&gt;
This data can later be used to identify specific products and create specific configuration for them, as in the [[EtherCAT:EC_INSTALL_STX_CDHD|CDHD Configuration example]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	numOfSlaves = EC_ETHERCAT_INIT&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Look for an unknown generic DS402 motion drive. If found, remap its PDOs to the required minimum.&amp;lt;br/&amp;gt;&lt;br /&gt;
You may update the following code by replacing the define GENERIC_DS402_DRIVE_VENDOR with your device's vendor ID, by doing so remapping its PDO's to the required minimum to create sync position motion:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	for drive_addr = 1 to numOfSlaves&lt;br /&gt;
		if ETSLAVES[drive_addr]-&amp;gt;et_slavetype = ECAT_MOTIONSLAVE then&lt;br /&gt;
			if EC_SLAVES_INFO[drive_addr]-&amp;gt;vendor_id = GENERIC_DS402_DRIVE_VENDOR then  '  replace with your product's vendor ID&lt;br /&gt;
				call EC_REMAP_MINIMUM_PDOS(drive_addr)&lt;br /&gt;
			end if&lt;br /&gt;
		end if&lt;br /&gt;
	next&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Check the EtherCAT Topology for Wiring Errors===&lt;br /&gt;
EtherCAT topology is sensitive to the direction of the wiring. Each EtherCAT slave has an INPUT connector and an OUTPUT connector.&amp;lt;br/&amp;gt;&lt;br /&gt;
The cable that &amp;quot;starts&amp;quot; from the EtherCAT master's OUTPUT must be connected to the INPUT of the first EtherCAT slave. A second cable will &amp;quot;exit&amp;quot; from the OUTPUT of the first slave and get connected to the INPUT of the second slave, etc...&amp;lt;br/&amp;gt;&lt;br /&gt;
'Miswiring' on most occasions means that somewhere in the topology the EtherCAT cable wiring got confused between the INPUT and the OUTPUT connectors.&amp;lt;br/&amp;gt;&lt;br /&gt;
This situation results UNDEFINED behavior, even up to making the wrong motor move, which is a safety issue.&lt;br /&gt;
{{Note/Important|If a miswiring is detected, an error will be thrown and EC_SETUP.PRG will stop running}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	retVal = CHECK_TOPOLOGY&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create the EtherCAT Master.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_CREATE_MASTER&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set Motion Cycle Time: 4000, 2000, 1000, 500 or 250 [us]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_SET_BUS_CYCLETIME(4000)  ' For a cycle time of 500/250[us], add to FWCONFIG: hpetfreq = 2000&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
From here on EC_SETUP.PRG uses the gathered information to configure the slaves. A 'For Loop' goes over the slaves and tries to match&lt;br /&gt;
them to already known products (such as the CDHD). When found, product specific functions are invoked to create data structures in the master that elaborate the PDO mapping of the slaves, be it a motion drive or an IO module. This is where you can add your own code to configure your own EtherCAT slave. Just add another case to match your Vendor ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
You may use the already prepared GENERIC_DS402_DRIVE_VENDOR case.&amp;lt;br/&amp;gt;&lt;br /&gt;
Replace the define GENERIC_DS402_DRIVE_VENDOR with your device's vendor ID, and GENERIC_DS402_DRIVE_PRODUCT_ID with the device's product code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
      Case GENERIC_DS402_DRIVE_VENDOR  '  replace with your vendor id&lt;br /&gt;
&lt;br /&gt;
        if EC_SLAVES_INFO[drive_addr]-&amp;gt;product_code = GENERIC_DS402_DRIVE_PRODUCT_ID then  '  replace with your product id&lt;br /&gt;
&lt;br /&gt;
          call EC_INSTALL_GENERIC_DRIVE(drive_addr, Counts_Per_Revolution)  '  Counts Per motor Revolution&lt;br /&gt;
          num_Of_Motion_Drives = num_Of_Motion_Drives + 1&lt;br /&gt;
&lt;br /&gt;
        end if&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If a Servotronix (STX) CDHD servo motion drive is found, the function [[EtherCAT:EC_INSTALL_STX_CDHD|EC_INSTALL_STX_CDHD]] is invoked. This function sets certain parameters in the drive, creates the PDO map of the CDHD, and queries the drive's PNUM and PDEN to allow calculation of the [[MC-Basic:axis.POSITIONFACTOR|Position Factor]].&lt;br /&gt;
&lt;br /&gt;
For a generic drive, a minimum PDO mapping and default values are used. &lt;br /&gt;
&lt;br /&gt;
The user can add his own code to [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]] to perform any specific configuration that must take place while the slaves are in PREOP mode.&lt;br /&gt;
&lt;br /&gt;
After the slave configuration is done the master is started:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' Create PDOs mapping, set bus cycle time, sync clocks between the master and the slaves,&lt;br /&gt;
	' raise slaves to OP-Mode and sets master's opmode to operational&lt;br /&gt;
	call EC_STARTMASTER  ' Syncs clocks between the master and the slaves, and sets master's opmode to operational&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The master attempts to raise all the slaves to OP Mode. If it fails, the procedure is stopped and an error is issued.&lt;br /&gt;
If it is successful, EtherCAT communication is now online and EC_SETUP.PRG starts the second stage of configuration.&lt;br /&gt;
&lt;br /&gt;
==OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Again, a For Loop goes over all the slaves. When a motion drive is encountered, EC_SETUP.PRG attaches its drive address to an axis and&lt;br /&gt;
attempts to clear its faults.&lt;br /&gt;
Again, the user can add his own code to [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]] and [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]] to perform any specific configuration that must take place while the slaves are in &amp;quot;SAFEOP&amp;quot; or &amp;quot;OP&amp;quot; mode.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' SAFEOP state configuration - Add code to EC_USER_SAFEOP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_SAFEOP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' OP state configuration - Add code to EC_USER_OP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_OP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' Assign slave address to an axis&lt;br /&gt;
	Axes[Axis_Attached_To_Drive].dadd = drive_addr&lt;br /&gt;
&lt;br /&gt;
	' Attempt to clear faults in the drives&lt;br /&gt;
	Try&lt;br /&gt;
&lt;br /&gt;
		call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	Catch Else&lt;br /&gt;
&lt;br /&gt;
		' if clear faults failed due to PLL Sync Error, wait a little longer and retry&lt;br /&gt;
		if EC_SDO_READ(drive_addr, 0x603f, 0) = 0x7386 then&lt;br /&gt;
			printu &amp;quot;PLL Error in drive #. Sleeping 5 seconds and retrying to clear fault&amp;quot;;drive_addr&lt;br /&gt;
			sleep 5000&lt;br /&gt;
			call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
		end if&lt;br /&gt;
&lt;br /&gt;
	End Try&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
All the motion drives are set to Synchronous Position Mode:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' Set drives to sync position mode&lt;br /&gt;
	if EC_IS_PDO(Axes[Axis_Attached_To_Drive].dadd, 0x6060, 0) then&lt;br /&gt;
		call EC_PDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8)&lt;br /&gt;
	else&lt;br /&gt;
		call EC_SDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8, 8)&lt;br /&gt;
	end if&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
* [[EtherCAT:EC ETHERCAT INIT|EC_ETHERCAT_INIT]]&lt;br /&gt;
* [[EtherCAT:EC REMAP MINIMUM PDOS|EC_REMAP_MINIMUM_PDOS]]&lt;br /&gt;
* [[EtherCAT:EC CREATE MASTER|EC_CREATE_MASTER]]&lt;br /&gt;
* [[EtherCAT:EC SET BUS CYCLETIME|EC_SET_BUS_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC GET BUS CYCLETIME|EC_SET_BUS_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC STARTMASTER|EC_STARTMASTER]]&lt;br /&gt;
* [[EtherCAT:EC CLEAR FAULTS|EC_CLEAR_FAULTS]]&lt;br /&gt;
* [[EtherCAT:EC SDO READ|EC_SDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC SDO WRITE|EC_SDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC PDO READ|EC_PDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC PDO WRITE|EC_PDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC IS PDO|EC_IS_PDO]]&lt;br /&gt;
* [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
[[Category:EtherCAT]]&lt;br /&gt;
[[Category:Control:Offline]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125795</id>
		<title>Category:EtherCAT:EC SETUP</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125795"/>
				<updated>2016-02-28T12:14:36Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Category&lt;br /&gt;
|description=How to Set up EtherCAT.&lt;br /&gt;
|frontpage=[[EtherCAT]]&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
Before starting to work with the softMC, you must setup the EtherCAT master to work with the slaves.&amp;lt;br/&amp;gt;&lt;br /&gt;
You must configure the axes in the system in a certain manner, then invoke certain functions and subroutines in an orderly manner, and make sure no errors occur.&lt;br /&gt;
&lt;br /&gt;
A CONFIG.PRG and a program file EC_SETUP.PRG exist in the repository, and demonstrate the following process.&lt;br /&gt;
&lt;br /&gt;
CONFIG.PRG allocates an array of generic axes by the name Axes[], and sets all the existing axes in the system into this array.&amp;lt;br/&amp;gt;&lt;br /&gt;
{{Note| Since verison 0.4.15.3rc6 the global axis array systemAxis[] is introduced, and the array Axes[] is made redundant, therefore it is removed from CONFIG.PRG }}&lt;br /&gt;
EC_SETUP.PRG and AX_SETUP.PRG use this array to setup the system automatically.&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
It is critical to maintain the demonstrated order of the EtherCAT setup.&amp;lt;br/&amp;gt;Any change in the given example may result in undefined behavior!}}&lt;br /&gt;
&lt;br /&gt;
==EC_SETUP.PRG==&lt;br /&gt;
EC_SETUP.PRG is a generic script. Its purpose is to configure the EtherCAT master and slaves before they are started, start the master, and eventually run additional actions to complete the EtherCAT startup procedure.&lt;br /&gt;
&lt;br /&gt;
EC_SETUP.PRG is written in a manner that easily allows embedding code to configure specific motion drives and IO modules.&lt;br /&gt;
&lt;br /&gt;
This article details the main steps that occur upon EtherCAT startup as they are executed by EC_SETUP.PRG.&lt;br /&gt;
&lt;br /&gt;
==Drive Address==&lt;br /&gt;
Each EtherCAT slave has an address. Currently this address is determined strictly according to the slave location in the&lt;br /&gt;
[[:File:Axystems;EC_master_slave_position_topology.PNG|physical topology]] of the system; that is, the first slave attached to the MC is assigned drive address 1, the second slave in the chain gets slave address 2, and so on. &lt;br /&gt;
&lt;br /&gt;
An EtherCAT slave can be a motion drive, an IO module or a Gateway.&lt;br /&gt;
&lt;br /&gt;
==PRE-OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Before the master is started all the slaves are in PRE-OP mode. In this stage the master is created and the system gathers information from the slaves in order to create data structures that are used by the master to set up the EtherCAT communication.&lt;br /&gt;
&lt;br /&gt;
First, differentiate between '''motion drives''' and '''IO modules'''. For each slave query the slave's Vendor ID and Product Code.&lt;br /&gt;
This data can later be used to identify specific products and create specific configuration for them, as in the [[EtherCAT:EC_INSTALL_STX_CDHD|CDHD Configuration example]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	numOfSlaves = EC_ETHERCAT_INIT&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Look for an unknown generic DS402 motion drive. If found, remap its PDOs to the required minimum.&amp;lt;br/&amp;gt;&lt;br /&gt;
You may update the following code by replacing the define GENERIC_DS402_DRIVE_VENDOR with your device's vendor ID, by doing so remapping its PDO's to the required minimum to create sync position motion:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	for drive_addr = 1 to numOfSlaves&lt;br /&gt;
		if ETSLAVES[drive_addr]-&amp;gt;et_slavetype = ECAT_MOTIONSLAVE then&lt;br /&gt;
			if EC_SLAVES_INFO[drive_addr]-&amp;gt;vendor_id = GENERIC_DS402_DRIVE_VENDOR then  '  replace with your product id&lt;br /&gt;
				call EC_REMAP_MINIMUM_PDOS(drive_addr)&lt;br /&gt;
			end if&lt;br /&gt;
		end if&lt;br /&gt;
	next&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Check the EtherCAT Topology for Wiring Errors===&lt;br /&gt;
EtherCAT topology is sensitive to the direction of the wiring. Each EtherCAT slave has an INPUT connector and an OUTPUT connector.&amp;lt;br/&amp;gt;&lt;br /&gt;
The cable that &amp;quot;starts&amp;quot; from the EtherCAT master's OUTPUT must be connected to the INPUT of the first EtherCAT slave. A second cable will &amp;quot;exit&amp;quot; from the OUTPUT of the first slave and get connected to the INPUT of the second slave, etc...&amp;lt;br/&amp;gt;&lt;br /&gt;
'Miswiring' on most occasions means that somewhere in the topology the EtherCAT cable wiring got confused between the INPUT and the OUTPUT connectors.&amp;lt;br/&amp;gt;&lt;br /&gt;
This situation results UNDEFINED behavior, even up to making the wrong motor move, which is a safety issue.&lt;br /&gt;
{{Note/Important|If a miswiring is detected, an error will be thrown and EC_SETUP.PRG will stop running}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	retVal = CHECK_TOPOLOGY&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create the EtherCAT Master.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_CREATE_MASTER&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set Motion Cycle Time: 4000, 2000, 1000, 500 or 250 [us]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_SET_BUS_CYCLETIME(4000)  ' For a cycle time of 500/250[us], add to FWCONFIG: hpetfreq = 2000&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
From here on EC_SETUP.PRG uses the gathered information to configure the slaves. A 'For Loop' goes over the slaves and tries to match&lt;br /&gt;
them to already known products (such as the CDHD). When found, product specific functions are invoked to create data structures in the master that elaborate the PDO mapping of the slaves, be it a motion drive or an IO module. This is where you can add your own code to configure your own EtherCAT slave. Just add another case to match your Vendor ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
You may use the already prepared GENERIC_DS402_DRIVE_VENDOR case.&amp;lt;br/&amp;gt;&lt;br /&gt;
Replace the define GENERIC_DS402_DRIVE_VENDOR with your device's vendor ID, and GENERIC_DS402_DRIVE_PRODUCT_ID with the device's product code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
      Case GENERIC_DS402_DRIVE_VENDOR  '  replace with your vendor id&lt;br /&gt;
&lt;br /&gt;
        if EC_SLAVES_INFO[drive_addr]-&amp;gt;product_code = GENERIC_DS402_DRIVE_PRODUCT_ID then  '  replace with your product id&lt;br /&gt;
&lt;br /&gt;
          call EC_INSTALL_GENERIC_DRIVE(drive_addr, Counts_Per_Revolution)  '  Counts Per motor Revolution&lt;br /&gt;
          num_Of_Motion_Drives = num_Of_Motion_Drives + 1&lt;br /&gt;
&lt;br /&gt;
        end if&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If a Servotronix (STX) CDHD servo motion drive is found, the function [[EtherCAT:EC_INSTALL_STX_CDHD|EC_INSTALL_STX_CDHD]] is invoked. This function sets certain parameters in the drive, creates the PDO map of the CDHD, and queries the drive's PNUM and PDEN to allow calculation of the [[MC-Basic:axis.POSITIONFACTOR|Position Factor]].&lt;br /&gt;
&lt;br /&gt;
For a generic drive, a minimum PDO mapping and default values are used. &lt;br /&gt;
&lt;br /&gt;
The user can add his own code to [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]] to perform any specific configuration that must take place while the slaves are in PREOP mode.&lt;br /&gt;
&lt;br /&gt;
After the slave configuration is done the master is started:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' Create PDOs mapping, set bus cycle time, sync clocks between the master and the slaves,&lt;br /&gt;
	' raise slaves to OP-Mode and sets master's opmode to operational&lt;br /&gt;
	call EC_STARTMASTER  ' Syncs clocks between the master and the slaves, and sets master's opmode to operational&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The master attempts to raise all the slaves to OP Mode. If it fails, the procedure is stopped and an error is issued.&lt;br /&gt;
If it is successful, EtherCAT communication is now online and EC_SETUP.PRG starts the second stage of configuration.&lt;br /&gt;
&lt;br /&gt;
==OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Again, a For Loop goes over all the slaves. When a motion drive is encountered, EC_SETUP.PRG attaches its drive address to an axis and&lt;br /&gt;
attempts to clear its faults.&lt;br /&gt;
Again, the user can add his own code to [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]] and [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]] to perform any specific configuration that must take place while the slaves are in &amp;quot;SAFEOP&amp;quot; or &amp;quot;OP&amp;quot; mode.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' SAFEOP state configuration - Add code to EC_USER_SAFEOP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_SAFEOP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' OP state configuration - Add code to EC_USER_OP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_OP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' Assign slave address to an axis&lt;br /&gt;
	Axes[Axis_Attached_To_Drive].dadd = drive_addr&lt;br /&gt;
&lt;br /&gt;
	' Attempt to clear faults in the drives&lt;br /&gt;
	Try&lt;br /&gt;
&lt;br /&gt;
		call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	Catch Else&lt;br /&gt;
&lt;br /&gt;
		' if clear faults failed due to PLL Sync Error, wait a little longer and retry&lt;br /&gt;
		if EC_SDO_READ(drive_addr, 0x603f, 0) = 0x7386 then&lt;br /&gt;
			printu &amp;quot;PLL Error in drive #. Sleeping 5 seconds and retrying to clear fault&amp;quot;;drive_addr&lt;br /&gt;
			sleep 5000&lt;br /&gt;
			call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
		end if&lt;br /&gt;
&lt;br /&gt;
	End Try&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
All the motion drives are set to Synchronous Position Mode:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' Set drives to sync position mode&lt;br /&gt;
	if EC_IS_PDO(Axes[Axis_Attached_To_Drive].dadd, 0x6060, 0) then&lt;br /&gt;
		call EC_PDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8)&lt;br /&gt;
	else&lt;br /&gt;
		call EC_SDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8, 8)&lt;br /&gt;
	end if&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
* [[EtherCAT:EC ETHERCAT INIT|EC_ETHERCAT_INIT]]&lt;br /&gt;
* [[EtherCAT:EC REMAP MINIMUM PDOS|EC_REMAP_MINIMUM_PDOS]]&lt;br /&gt;
* [[EtherCAT:EC CREATE MASTER|EC_CREATE_MASTER]]&lt;br /&gt;
* [[EtherCAT:EC SET BUS CYCLETIME|EC_SET_BUS_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC GET BUS CYCLETIME|EC_SET_BUS_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC STARTMASTER|EC_STARTMASTER]]&lt;br /&gt;
* [[EtherCAT:EC CLEAR FAULTS|EC_CLEAR_FAULTS]]&lt;br /&gt;
* [[EtherCAT:EC SDO READ|EC_SDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC SDO WRITE|EC_SDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC PDO READ|EC_PDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC PDO WRITE|EC_PDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC IS PDO|EC_IS_PDO]]&lt;br /&gt;
* [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
[[Category:EtherCAT]]&lt;br /&gt;
[[Category:Control:Offline]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125794</id>
		<title>Category:EtherCAT:EC SETUP</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125794"/>
				<updated>2016-02-28T12:11:58Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Category&lt;br /&gt;
|description=How to Set up EtherCAT.&lt;br /&gt;
|frontpage=[[EtherCAT]]&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
Before starting to work with the softMC, you must setup the EtherCAT master to work with the slaves.&amp;lt;br/&amp;gt;&lt;br /&gt;
You must configure the axes in the system in a certain manner, then invoke certain functions and subroutines in an orderly manner, and make sure no errors occur.&lt;br /&gt;
&lt;br /&gt;
A CONFIG.PRG and a program file EC_SETUP.PRG exist in the repository, and demonstrate the following process.&lt;br /&gt;
&lt;br /&gt;
CONFIG.PRG allocates an array of generic axes by the name Axes[], and sets all the existing axes in the system into this array.&amp;lt;br/&amp;gt;&lt;br /&gt;
{{Note| Since verison 0.4.15.3rc6 the global axis array systemAxis[] is introduced, and the array Axes[] is made redundant, therefore it is removed from CONFIG.PRG }}&lt;br /&gt;
EC_SETUP.PRG and AX_SETUP.PRG use this array to setup the system automatically.&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
It is critical to maintain the demonstrated order of the EtherCAT setup.&amp;lt;br/&amp;gt;Any change in the given example may result in undefined behavior!}}&lt;br /&gt;
&lt;br /&gt;
==EC_SETUP.PRG==&lt;br /&gt;
EC_SETUP.PRG is a generic script. Its purpose is to configure the EtherCAT master and slaves before they are started, start the master, and eventually run additional actions to complete the EtherCAT startup procedure.&lt;br /&gt;
&lt;br /&gt;
EC_SETUP.PRG is written in a manner that easily allows embedding code to configure specific motion drives and IO modules.&lt;br /&gt;
&lt;br /&gt;
This article details the main steps that occur upon EtherCAT startup as they are executed by EC_SETUP.PRG.&lt;br /&gt;
&lt;br /&gt;
==Drive Address==&lt;br /&gt;
Each EtherCAT slave has an address. Currently this address is determined strictly according to the slave location in the&lt;br /&gt;
[[:File:Axystems;EC_master_slave_position_topology.PNG|physical topology]] of the system; that is, the first slave attached to the MC is assigned drive address 1, the second slave in the chain gets slave address 2, and so on. &lt;br /&gt;
&lt;br /&gt;
An EtherCAT slave can be a motion drive, an IO module or a Gateway.&lt;br /&gt;
&lt;br /&gt;
==PRE-OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Before the master is started all the slaves are in PRE-OP mode. In this stage the master is created and the system gathers information from the slaves in order to create data structures that are used by the master to set up the EtherCAT communication.&lt;br /&gt;
&lt;br /&gt;
First, differentiate between '''motion drives''' and '''IO modules'''. For each slave query the slave's Vendor ID and Product Code.&lt;br /&gt;
This data can later be used to identify specific products and create specific configuration for them, as in the [[EtherCAT:EC_INSTALL_STX_CDHD|CDHD Configuration example]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	numOfSlaves = EC_ETHERCAT_INIT&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Look for an unknown generic DS402 motion drive. If found, remap its PDOs to the required minimum.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	for drive_addr = 1 to numOfSlaves&lt;br /&gt;
		if ETSLAVES[drive_addr]-&amp;gt;et_slavetype = ECAT_MOTIONSLAVE then&lt;br /&gt;
			if EC_SLAVES_INFO[drive_addr]-&amp;gt;vendor_id = GENERIC_DS402_DRIVE_VENDOR then&lt;br /&gt;
				call EC_REMAP_MINIMUM_PDOS(drive_addr)&lt;br /&gt;
			end if&lt;br /&gt;
		end if&lt;br /&gt;
	next&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Check the EtherCAT Topology for Wiring Errors===&lt;br /&gt;
EtherCAT topology is sensitive to the direction of the wiring. Each EtherCAT slave has an INPUT connector and an OUTPUT connector.&amp;lt;br/&amp;gt;&lt;br /&gt;
The cable that &amp;quot;starts&amp;quot; from the EtherCAT master's OUTPUT must be connected to the INPUT of the first EtherCAT slave. A second cable will &amp;quot;exit&amp;quot; from the OUTPUT of the first slave and get connected to the INPUT of the second slave, etc...&amp;lt;br/&amp;gt;&lt;br /&gt;
'Miswiring' on most occasions means that somewhere in the topology the EtherCAT cable wiring got confused between the INPUT and the OUTPUT connectors.&amp;lt;br/&amp;gt;&lt;br /&gt;
This situation results UNDEFINED behavior, even up to making the wrong motor move, which is a safety issue.&lt;br /&gt;
{{Note/Important|If a miswiring is detected, an error will be thrown and EC_SETUP.PRG will stop running}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	retVal = CHECK_TOPOLOGY&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create the EtherCAT Master.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_CREATE_MASTER&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set Motion Cycle Time: 4000, 2000, 1000, 500 or 250 [us]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_SET_BUS_CYCLETIME(4000)  ' For a cycle time of 500/250[us], add to FWCONFIG: hpetfreq = 2000&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
From here on EC_SETUP.PRG uses the gathered information to configure the slaves. A 'For Loop' goes over the slaves and tries to match&lt;br /&gt;
them to already known products (such as the CDHD). When found, product specific functions are invoked to create data structures in the master that elaborate the PDO mapping of the slaves, be it a motion drive or an IO module. This is where you can add your own code to configure your own EtherCAT slave. Just add another case to match your Vendor ID.&amp;lt;br/&amp;gt;&lt;br /&gt;
You may use the already prepared GENERIC_DS402_DRIVE_VENDOR case.&amp;lt;br/&amp;gt;&lt;br /&gt;
Replace the define GENERIC_DS402_DRIVE_VENDOR with your device's vendor ID, and GENERIC_DS402_DRIVE_PRODUCT_ID with the device's product code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
      Case GENERIC_DS402_DRIVE_VENDOR  '  replace with your vendor id&lt;br /&gt;
&lt;br /&gt;
        if EC_SLAVES_INFO[drive_addr]-&amp;gt;product_code = GENERIC_DS402_DRIVE_PRODUCT_ID then  '  replace with your product id&lt;br /&gt;
&lt;br /&gt;
          call EC_INSTALL_GENERIC_DRIVE(drive_addr, Counts_Per_Revolution)  '  Counts Per motor Revolution&lt;br /&gt;
          num_Of_Motion_Drives = num_Of_Motion_Drives + 1&lt;br /&gt;
&lt;br /&gt;
        end if&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If a Servotronix (STX) CDHD servo motion drive is found, the function [[EtherCAT:EC_INSTALL_STX_CDHD|EC_INSTALL_STX_CDHD]] is invoked. This function sets certain parameters in the drive, creates the PDO map of the CDHD, and queries the drive's PNUM and PDEN to allow calculation of the [[MC-Basic:axis.POSITIONFACTOR|Position Factor]].&lt;br /&gt;
&lt;br /&gt;
For a generic drive, a minimum PDO mapping and default values are used. &lt;br /&gt;
&lt;br /&gt;
The user can add his own code to [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]] to perform any specific configuration that must take place while the slaves are in PREOP mode.&lt;br /&gt;
&lt;br /&gt;
After the slave configuration is done the master is started:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' Create PDOs mapping, set bus cycle time, sync clocks between the master and the slaves,&lt;br /&gt;
	' raise slaves to OP-Mode and sets master's opmode to operational&lt;br /&gt;
	call EC_STARTMASTER  ' Syncs clocks between the master and the slaves, and sets master's opmode to operational&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The master attempts to raise all the slaves to OP Mode. If it fails, the procedure is stopped and an error is issued.&lt;br /&gt;
If it is successful, EtherCAT communication is now online and EC_SETUP.PRG starts the second stage of configuration.&lt;br /&gt;
&lt;br /&gt;
==OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Again, a For Loop goes over all the slaves. When a motion drive is encountered, EC_SETUP.PRG attaches its drive address to an axis and&lt;br /&gt;
attempts to clear its faults.&lt;br /&gt;
Again, the user can add his own code to [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]] and [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]] to perform any specific configuration that must take place while the slaves are in &amp;quot;SAFEOP&amp;quot; or &amp;quot;OP&amp;quot; mode.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' SAFEOP state configuration - Add code to EC_USER_SAFEOP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_SAFEOP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' OP state configuration - Add code to EC_USER_OP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_OP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' Assign slave address to an axis&lt;br /&gt;
	Axes[Axis_Attached_To_Drive].dadd = drive_addr&lt;br /&gt;
&lt;br /&gt;
	' Attempt to clear faults in the drives&lt;br /&gt;
	Try&lt;br /&gt;
&lt;br /&gt;
		call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	Catch Else&lt;br /&gt;
&lt;br /&gt;
		' if clear faults failed due to PLL Sync Error, wait a little longer and retry&lt;br /&gt;
		if EC_SDO_READ(drive_addr, 0x603f, 0) = 0x7386 then&lt;br /&gt;
			printu &amp;quot;PLL Error in drive #. Sleeping 5 seconds and retrying to clear fault&amp;quot;;drive_addr&lt;br /&gt;
			sleep 5000&lt;br /&gt;
			call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
		end if&lt;br /&gt;
&lt;br /&gt;
	End Try&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
All the motion drives are set to Synchronous Position Mode:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' Set drives to sync position mode&lt;br /&gt;
	if EC_IS_PDO(Axes[Axis_Attached_To_Drive].dadd, 0x6060, 0) then&lt;br /&gt;
		call EC_PDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8)&lt;br /&gt;
	else&lt;br /&gt;
		call EC_SDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8, 8)&lt;br /&gt;
	end if&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
* [[EtherCAT:EC ETHERCAT INIT|EC_ETHERCAT_INIT]]&lt;br /&gt;
* [[EtherCAT:EC REMAP MINIMUM PDOS|EC_REMAP_MINIMUM_PDOS]]&lt;br /&gt;
* [[EtherCAT:EC CREATE MASTER|EC_CREATE_MASTER]]&lt;br /&gt;
* [[EtherCAT:EC SET BUS CYCLETIME|EC_SET_BUS_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC GET BUS CYCLETIME|EC_SET_BUS_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC STARTMASTER|EC_STARTMASTER]]&lt;br /&gt;
* [[EtherCAT:EC CLEAR FAULTS|EC_CLEAR_FAULTS]]&lt;br /&gt;
* [[EtherCAT:EC SDO READ|EC_SDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC SDO WRITE|EC_SDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC PDO READ|EC_PDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC PDO WRITE|EC_PDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC IS PDO|EC_IS_PDO]]&lt;br /&gt;
* [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
[[Category:EtherCAT]]&lt;br /&gt;
[[Category:Control:Offline]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125793</id>
		<title>Category:EtherCAT:EC SETUP</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125793"/>
				<updated>2016-02-28T12:03:44Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Category&lt;br /&gt;
|description=How to Set up EtherCAT.&lt;br /&gt;
|frontpage=[[EtherCAT]]&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
Before starting to work with the softMC, you must setup the EtherCAT master to work with the slaves.&amp;lt;br/&amp;gt;&lt;br /&gt;
You must configure the axes in the system in a certain manner, then invoke certain functions and subroutines in an orderly manner, and make sure no errors occur.&lt;br /&gt;
&lt;br /&gt;
A CONFIG.PRG and a program file EC_SETUP.PRG exist in the repository, and demonstrate the following process.&lt;br /&gt;
&lt;br /&gt;
CONFIG.PRG allocates an array of generic axes by the name Axes[], and sets all the existing axes in the system into this array.&amp;lt;br/&amp;gt;&lt;br /&gt;
{{Note| Since verison 0.4.15.3rc6 the global axis array systemAxis[] is introduced, and the array Axes[] is made redundant, therefore it is removed from CONFIG.PRG }}&lt;br /&gt;
EC_SETUP.PRG and AX_SETUP.PRG use this array to setup the system automatically.&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
It is critical to maintain the demonstrated order of the EtherCAT setup.&amp;lt;br/&amp;gt;Any change in the given example may result in undefined behavior!}}&lt;br /&gt;
&lt;br /&gt;
==EC_SETUP.PRG==&lt;br /&gt;
EC_SETUP.PRG is a generic script. Its purpose is to configure the EtherCAT master and slaves before they are started, start the master, and eventually run additional actions to complete the EtherCAT startup procedure.&lt;br /&gt;
&lt;br /&gt;
EC_SETUP.PRG is written in a manner that easily allows embedding code to configure specific motion drives and IO modules.&lt;br /&gt;
&lt;br /&gt;
This article details the main steps that occur upon EtherCAT startup as they are executed by EC_SETUP.PRG.&lt;br /&gt;
&lt;br /&gt;
==Drive Address==&lt;br /&gt;
Each EtherCAT slave has an address. Currently this address is determined strictly according to the slave location in the&lt;br /&gt;
[[:File:Axystems;EC_master_slave_position_topology.PNG|physical topology]] of the system; that is, the first slave attached to the MC is assigned drive address 1, the second slave in the chain gets slave address 2, and so on. &lt;br /&gt;
&lt;br /&gt;
An EtherCAT slave can be a motion drive, an IO module or a Gateway.&lt;br /&gt;
&lt;br /&gt;
==PRE-OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Before the master is started all the slaves are in PRE-OP mode. In this stage the master is created and the system gathers information from the slaves in order to create data structures that are used by the master to set up the EtherCAT communication.&lt;br /&gt;
&lt;br /&gt;
First, differentiate between '''motion drives''' and '''IO modules'''. For each slave query the slave's Vendor ID and Product Code.&lt;br /&gt;
This data can later be used to identify specific products and create specific configuration for them, as in the [[EtherCAT:EC_INSTALL_STX_CDHD|CDHD Configuration example]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	numOfSlaves = EC_ETHERCAT_INIT&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Look for an unknown generic DS402 motion drive. If found, remap its PDOs to the required minimum.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	for drive_addr = 1 to numOfSlaves&lt;br /&gt;
		if ETSLAVES[drive_addr]-&amp;gt;et_slavetype = ECAT_MOTIONSLAVE then&lt;br /&gt;
			if EC_SLAVES_INFO[drive_addr]-&amp;gt;vendor_id = GENERIC_DS402_DRIVE_VENDOR then&lt;br /&gt;
				call EC_REMAP_MINIMUM_PDOS(drive_addr)&lt;br /&gt;
			end if&lt;br /&gt;
		end if&lt;br /&gt;
	next&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Check the EtherCAT Topology for Wiring Errors===&lt;br /&gt;
EtherCAT topology is sensitive to the direction of the wiring. Each EtherCAT slave has an INPUT connector and an OUTPUT connector.&amp;lt;br/&amp;gt;&lt;br /&gt;
The cable that &amp;quot;starts&amp;quot; from the EtherCAT master's OUTPUT must be connected to the INPUT of the first EtherCAT slave. A second cable will &amp;quot;exit&amp;quot; from the OUTPUT of the first slave and get connected to the INPUT of the second slave, etc...&amp;lt;br/&amp;gt;&lt;br /&gt;
'Miswiring' on most occasions means that somewhere in the topology the EtherCAT cable wiring got confused between the INPUT and the OUTPUT connectors.&amp;lt;br/&amp;gt;&lt;br /&gt;
This situation results UNDEFINED behavior, even up to making the wrong motor move, which is a safety issue.&lt;br /&gt;
{{Note/Important|If a miswiring is detected, an error will be thrown and EC_SETUP.PRG will stop running}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	retVal = CHECK_TOPOLOGY&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create the EtherCAT Master.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_CREATE_MASTER&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set Motion Cycle Time: 4000, 2000, 1000, 500 or 250 [us]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_SET_BUS_CYCLETIME(4000)  ' For a cycle time of 500/250[us], add to FWCONFIG: hpetfreq = 2000&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
From here on EC_SETUP.PRG uses the gathered information to configure the slaves. A 'For Loop' goes over the slaves and tries to match&lt;br /&gt;
them to already known products (such as the CDHD). When found, product specific functions are invoked to create data structures in the master that elaborate the PDO mapping of the slaves, be it a motion drive or an IO module. This is where you can add your own code to configure your own EtherCAT slave. Just add another case to match your Vendor ID.&lt;br /&gt;
&lt;br /&gt;
If a Servotronix (STX) CDHD servo motion drive is found, the function [[EtherCAT:EC_INSTALL_STX_CDHD|EC_INSTALL_STX_CDHD]] is invoked. This function sets certain parameters in the drive, creates the PDO map of the CDHD, and queries the drive's PNUM and PDEN to allow calculation of the [[MC-Basic:axis.POSITIONFACTOR|Position Factor]].&lt;br /&gt;
&lt;br /&gt;
For a generic drive, a minimum PDO mapping and default values are used. &lt;br /&gt;
&lt;br /&gt;
The user can add his own code to [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]] to perform any specific configuration that must take place while the slaves are in PREOP mode.&lt;br /&gt;
&lt;br /&gt;
After the slave configuration is done, a few more subroutines are called sequentially to complete the master's preparation,&lt;br /&gt;
and the master is started:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_ASSIGN_PDOS_AUTO&lt;br /&gt;
&lt;br /&gt;
	' After telling the master which slaves we want to work with, we create the PDO map&lt;br /&gt;
	call EC_CREATE_PDOS_MAP&lt;br /&gt;
&lt;br /&gt;
	call EC_SET_CYCLETIME  ' Set EtherCAT cycle time&lt;br /&gt;
&lt;br /&gt;
	' Raise slaves to OP-Mode&lt;br /&gt;
	call EC_STARTMASTER  ' Syncs clocks between the master and the slaves, and sets master's opmode to operational&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The master attempts to raise all the slaves to OP Mode. If it fails, the procedure is stopped and an error is issued.&lt;br /&gt;
If it is successful, EtherCAT communication is now online and EC_SETUP.PRG starts the second stage of configuration.&lt;br /&gt;
&lt;br /&gt;
==OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Again, a For Loop goes over all the slaves. When a motion drive is encountered, EC_SETUP.PRG attaches its drive address to an axis and&lt;br /&gt;
attempts to clear its faults.&lt;br /&gt;
Again, the user can add his own code to [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]] and [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]] to perform any specific configuration that must take place while the slaves are in &amp;quot;SAFEOP&amp;quot; or &amp;quot;OP&amp;quot; mode.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' SAFEOP state configuration - Add code to EC_USER_SAFEOP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_SAFEOP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' OP state configuration - Add code to EC_USER_OP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_OP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' Assign slave address to an axis&lt;br /&gt;
	Axes[Axis_Attached_To_Drive].dadd = drive_addr&lt;br /&gt;
&lt;br /&gt;
	' Attempt to clear faults in the drives&lt;br /&gt;
	Try&lt;br /&gt;
&lt;br /&gt;
		call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	Catch Else&lt;br /&gt;
&lt;br /&gt;
		' if clear faults failed due to PLL Sync Error, wait a little longer and retry&lt;br /&gt;
		if EC_SDO_READ(drive_addr, 0x603f, 0) = 0x7386 then&lt;br /&gt;
			printu &amp;quot;PLL Error in drive #. Sleeping 5 seconds and retrying to clear fault&amp;quot;;drive_addr&lt;br /&gt;
			sleep 5000&lt;br /&gt;
			call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
		end if&lt;br /&gt;
&lt;br /&gt;
	End Try&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
All the motion drives are set to Synchronous Position Mode:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' Set drives to sync position mode&lt;br /&gt;
	if EC_IS_PDO(Axes[Axis_Attached_To_Drive].dadd, 0x6060, 0) then&lt;br /&gt;
		call EC_PDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8)&lt;br /&gt;
	else&lt;br /&gt;
		call EC_SDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8, 8)&lt;br /&gt;
	end if&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
* [[EtherCAT:EC ETHERCAT INIT|EC_ETHERCAT_INIT]]&lt;br /&gt;
* [[EtherCAT:EC REMAP MINIMUM PDOS|EC_REMAP_MINIMUM_PDOS]]&lt;br /&gt;
* [[EtherCAT:EC CREATE MASTER|EC_CREATE_MASTER]]&lt;br /&gt;
* [[EtherCAT:EC SET BUS CYCLETIME|EC_SET_BUS_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC GET BUS CYCLETIME|EC_SET_BUS_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC STARTMASTER|EC_STARTMASTER]]&lt;br /&gt;
* [[EtherCAT:EC CLEAR FAULTS|EC_CLEAR_FAULTS]]&lt;br /&gt;
* [[EtherCAT:EC SDO READ|EC_SDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC SDO WRITE|EC_SDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC PDO READ|EC_PDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC PDO WRITE|EC_PDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC IS PDO|EC_IS_PDO]]&lt;br /&gt;
* [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
[[Category:EtherCAT]]&lt;br /&gt;
[[Category:Control:Offline]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=EtherCAT:EC_CREATE_MASTER&amp;diff=125792</id>
		<title>EtherCAT:EC CREATE MASTER</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=EtherCAT:EC_CREATE_MASTER&amp;diff=125792"/>
				<updated>2016-02-28T12:02:34Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:EtherCAT-Function&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
Create EtherCAT master within the firmware. This subroutine must be invoked, but it returns no useful information to the user.&lt;br /&gt;
&lt;br /&gt;
|INPUT=&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
|OUTPUT=&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
|RETURN VALUE=&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
|DECLARATION=&lt;br /&gt;
public subroutine EC_CREATE_MASTER&lt;br /&gt;
&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
call EC_CREATE_MASTER&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=EtherCAT:EC_CREATE_MASTER&amp;diff=125791</id>
		<title>EtherCAT:EC CREATE MASTER</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=EtherCAT:EC_CREATE_MASTER&amp;diff=125791"/>
				<updated>2016-02-28T12:01:35Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: Created page with &amp;quot;{{Template:EtherCAT-Function  |DESCRIPTION= Create EtherCAT master within the firmware. This subroutine must be invoked, but it returns no useful information to the user.  |IN...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:EtherCAT-Function&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
Create EtherCAT master within the firmware. This subroutine must be invoked, but it returns no useful information to the user.&lt;br /&gt;
&lt;br /&gt;
|INPUT=&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
|OUTPUT=&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
|RETURN VALUE=&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
|DECLARATION=&lt;br /&gt;
public subroutine EC_CREATE_MASTER as string&lt;br /&gt;
&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
call EC_CREATE_MASTER&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125790</id>
		<title>Category:EtherCAT:EC SETUP</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125790"/>
				<updated>2016-02-28T10:41:37Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Category&lt;br /&gt;
|description=How to Set up EtherCAT.&lt;br /&gt;
|frontpage=[[EtherCAT]]&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
Before starting to work with the softMC, you must setup the EtherCAT master to work with the slaves.&amp;lt;br/&amp;gt;&lt;br /&gt;
You must configure the axes in the system in a certain manner, then invoke certain functions and subroutines in an orderly manner, and make sure no errors occur.&lt;br /&gt;
&lt;br /&gt;
A CONFIG.PRG and a program file EC_SETUP.PRG exist in the repository, and demonstrate the following process.&lt;br /&gt;
&lt;br /&gt;
CONFIG.PRG allocates an array of generic axes by the name Axes[], and sets all the existing axes in the system into this array.&amp;lt;br/&amp;gt;&lt;br /&gt;
{{Note| Since verison 0.4.15.3rc6 the global axis array systemAxis[] is introduced, and the array Axes[] is made redundant, therefore it is removed from CONFIG.PRG }}&lt;br /&gt;
EC_SETUP.PRG and AX_SETUP.PRG use this array to setup the system automatically.&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
It is critical to maintain the demonstrated order of the EtherCAT setup.&amp;lt;br/&amp;gt;Any change in the given example may result in undefined behavior!}}&lt;br /&gt;
&lt;br /&gt;
==EC_SETUP.PRG==&lt;br /&gt;
EC_SETUP.PRG is a generic script. Its purpose is to configure the EtherCAT master and slaves before they are started, start the master, and eventually run additional actions to complete the EtherCAT startup procedure.&lt;br /&gt;
&lt;br /&gt;
EC_SETUP.PRG is written in a manner that easily allows embedding code to configure specific motion drives and IO modules.&lt;br /&gt;
&lt;br /&gt;
This article details the main steps that occur upon EtherCAT startup as they are executed by EC_SETUP.PRG.&lt;br /&gt;
&lt;br /&gt;
==Drive Address==&lt;br /&gt;
Each EtherCAT slave has an address. Currently this address is determined strictly according to the slave location in the&lt;br /&gt;
[[:File:Axystems;EC_master_slave_position_topology.PNG|physical topology]] of the system; that is, the first slave attached to the MC is assigned drive address 1, the second slave in the chain gets slave address 2, and so on. &lt;br /&gt;
&lt;br /&gt;
An EtherCAT slave can be a motion drive or an IO module.&lt;br /&gt;
&lt;br /&gt;
==PRE-OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Before the master is started all the slaves are in PRE-OP mode. In this stage the master is created and the system gathers information from the slaves in order to create data structures that are used by the master to set up the EtherCAT communication.&lt;br /&gt;
&lt;br /&gt;
First, differentiate between '''motion drives''' and '''IO modules'''. For each slave query the slave's Vendor ID and Product Code.&lt;br /&gt;
This data can later be used to identify specific products and create specific configuration for them, as in the [[EtherCAT:EC_INSTALL_STX_CDHD|CDHD Configuration example]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	numOfSlaves = EC_ETHERCAT_INIT&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Look for an unknown generic DS402 motion drive. If found, remap its PDOs to the required minimum.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	for drive_addr = 1 to numOfSlaves&lt;br /&gt;
		if ETSLAVES[drive_addr]-&amp;gt;et_slavetype = ECAT_MOTIONSLAVE then&lt;br /&gt;
			if EC_SLAVES_INFO[drive_addr]-&amp;gt;vendor_id = GENERIC_DS402_DRIVE_VENDOR then&lt;br /&gt;
				call EC_REMAP_MINIMUM_PDOS(drive_addr)&lt;br /&gt;
			end if&lt;br /&gt;
		end if&lt;br /&gt;
	next&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Check the EtherCAT Topology for Wiring Errors===&lt;br /&gt;
EtherCAT topology is sensitive to the direction of the wiring. Each EtherCAT slave has an INPUT connector and an OUTPUT connector.&amp;lt;br/&amp;gt;&lt;br /&gt;
The cable that &amp;quot;starts&amp;quot; from the EtherCAT master's OUTPUT must be connected to the INPUT of the first EtherCAT slave. A second cable will &amp;quot;exit&amp;quot; from the OUTPUT of the first slave and get connected to the INPUT of the second slave, etc...&amp;lt;br/&amp;gt;&lt;br /&gt;
'Miswiring' on most occasions means that somewhere in the topology the EtherCAT cable wiring got confused between the INPUT and the OUTPUT connectors.&amp;lt;br/&amp;gt;&lt;br /&gt;
This situation results UNDEFINED behavior, even up to making the wrong motor move, which is a safety issue.&lt;br /&gt;
{{Note/Important|If a miswiring is detected, an error will be thrown and EC_SETUP.PRG will stop running}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	retVal = CHECK_TOPOLOGY&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create the EtherCAT Master.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_CREATE_MASTER&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set Motion Cycle Time: 4000, 2000, 1000, 500 or 250 [us]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_SET_BUS_CYCLETIME(4000)  ' For a cycle time of 500/250[us], add to FWCONFIG: hpetfreq = 2000&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
From here on EC_SETUP.PRG uses the gathered information to configure the slaves. A 'For Loop' goes over the slaves and tries to match&lt;br /&gt;
them to already known products (such as the CDHD). When found, product specific functions are invoked to create data structures in the master that elaborate the PDO mapping of the slaves, be it a motion drive or an IO module. This is where you can add your own code to configure your own EtherCAT slave. Just add another case to match your Vendor ID.&lt;br /&gt;
&lt;br /&gt;
If a Servotronix (STX) CDHD servo motion drive is found, the function [[EtherCAT:EC_INSTALL_STX_CDHD|EC_INSTALL_STX_CDHD]] is invoked. This function sets certain parameters in the drive, creates the PDO map of the CDHD, and queries the drive's PNUM and PDEN to allow calculation of the [[MC-Basic:axis.POSITIONFACTOR|Position Factor]].&lt;br /&gt;
&lt;br /&gt;
For a generic drive, a minimum PDO mapping and default values are used. &lt;br /&gt;
&lt;br /&gt;
The user can add his own code to [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]] to perform any specific configuration that must take place while the slaves are in PREOP mode.&lt;br /&gt;
&lt;br /&gt;
After the slave configuration is done, a few more subroutines are called sequentially to complete the master's preparation,&lt;br /&gt;
and the master is started:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_ASSIGN_PDOS_AUTO&lt;br /&gt;
&lt;br /&gt;
	' After telling the master which slaves we want to work with, we create the PDO map&lt;br /&gt;
	call EC_CREATE_PDOS_MAP&lt;br /&gt;
&lt;br /&gt;
	call EC_SET_CYCLETIME  ' Set EtherCAT cycle time&lt;br /&gt;
&lt;br /&gt;
	' Raise slaves to OP-Mode&lt;br /&gt;
	call EC_STARTMASTER  ' Syncs clocks between the master and the slaves, and sets master's opmode to operational&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The master attempts to raise all the slaves to OP Mode. If it fails, the procedure is stopped and an error is issued.&lt;br /&gt;
If it is successful, EtherCAT communication is now online and EC_SETUP.PRG starts the second stage of configuration.&lt;br /&gt;
&lt;br /&gt;
==OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Again, a For Loop goes over all the slaves. When a motion drive is encountered, EC_SETUP.PRG attaches its drive address to an axis and&lt;br /&gt;
attempts to clear its faults.&lt;br /&gt;
Again, the user can add his own code to [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]] and [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]] to perform any specific configuration that must take place while the slaves are in &amp;quot;SAFEOP&amp;quot; or &amp;quot;OP&amp;quot; mode.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' SAFEOP state configuration - Add code to EC_USER_SAFEOP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_SAFEOP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' OP state configuration - Add code to EC_USER_OP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_OP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' Assign slave address to an axis&lt;br /&gt;
	Axes[Axis_Attached_To_Drive].dadd = drive_addr&lt;br /&gt;
&lt;br /&gt;
	' Attempt to clear faults in the drives&lt;br /&gt;
	Try&lt;br /&gt;
&lt;br /&gt;
		call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	Catch Else&lt;br /&gt;
&lt;br /&gt;
		' if clear faults failed due to PLL Sync Error, wait a little longer and retry&lt;br /&gt;
		if EC_SDO_READ(drive_addr, 0x603f, 0) = 0x7386 then&lt;br /&gt;
			printu &amp;quot;PLL Error in drive #. Sleeping 5 seconds and retrying to clear fault&amp;quot;;drive_addr&lt;br /&gt;
			sleep 5000&lt;br /&gt;
			call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
		end if&lt;br /&gt;
&lt;br /&gt;
	End Try&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
All the motion drives are set to Synchronous Position Mode:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' Set drives to sync position mode&lt;br /&gt;
	if EC_IS_PDO(Axes[Axis_Attached_To_Drive].dadd, 0x6060, 0) then&lt;br /&gt;
		call EC_PDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8)&lt;br /&gt;
	else&lt;br /&gt;
		call EC_SDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8, 8)&lt;br /&gt;
	end if&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
* [[EtherCAT:EC ETHERCAT INIT|EC_ETHERCAT_INIT]]&lt;br /&gt;
* [[EtherCAT:EC REMAP MINIMUM PDOS|EC_REMAP_MINIMUM_PDOS]]&lt;br /&gt;
* [[EtherCAT:EC CREATE MASTER|EC_CREATE_MASTER]]&lt;br /&gt;
* [[EtherCAT:EC SET BUS CYCLETIME|EC_SET_BUS_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC GET BUS CYCLETIME|EC_SET_BUS_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC STARTMASTER|EC_STARTMASTER]]&lt;br /&gt;
* [[EtherCAT:EC CLEAR FAULTS|EC_CLEAR_FAULTS]]&lt;br /&gt;
* [[EtherCAT:EC SDO READ|EC_SDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC SDO WRITE|EC_SDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC PDO READ|EC_PDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC PDO WRITE|EC_PDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC IS PDO|EC_IS_PDO]]&lt;br /&gt;
* [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
[[Category:EtherCAT]]&lt;br /&gt;
[[Category:Control:Offline]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=EtherCAT:EC_REMAP_MINIMUM_PDOS&amp;diff=125789</id>
		<title>EtherCAT:EC REMAP MINIMUM PDOS</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=EtherCAT:EC_REMAP_MINIMUM_PDOS&amp;diff=125789"/>
				<updated>2016-02-28T10:37:30Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:EtherCAT-Function&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
This subroutine remaps the PDO's of a certain drive to the required minimum objects that allow sync position mode.&amp;lt;br/&amp;gt;&lt;br /&gt;
These objects are:&amp;lt;br/&amp;gt;&lt;br /&gt;
Rx - Control Word 0x6040;0x0, Position Command 0x607A;0x0&amp;lt;br/&amp;gt;&lt;br /&gt;
Tx - Status Word 0x6041;0x0, Position Feedback 0x6064;0x0, Digital Inputs 0x60FD;0x0&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use this subroutine when integrating a softMC with a new or unknown motion drive to make sure it has the required minimum PDO entries to allow sync position motion.&lt;br /&gt;
&lt;br /&gt;
{{Note|&lt;br /&gt;
Use this subroutine as an example how to create you own PDO mapping}}&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
This subroutine must be invoked before [[:Category:EtherCAT:EC SETUP|EC_SETUP.PRG]] is executed, or right at the beginning of it, to allow MC to first rescan the slaves and get updated with the new PDO mapping of the devices}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|INPUT=&lt;br /&gt;
Slave address&lt;br /&gt;
&lt;br /&gt;
|OUTPUT=&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
|RETURN VALUE=&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
|DECLARATION=&lt;br /&gt;
Public Sub EC_REMAP_MINIMUM_PDOS(byval drive_addr as long)&lt;br /&gt;
&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
call EC_REMAP_MINIMUM_PDOS(&amp;lt;Slave address&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
|EXAMPLE=&lt;br /&gt;
call EC_REMAP_MINIMUM_PDOS(2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
* [[:Category:EtherCAT:EC SETUP|Setup EtherCAT]] - How to setup EtherCAT&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=EtherCAT:EC_REMAP_MINIMUM_PDOS&amp;diff=125788</id>
		<title>EtherCAT:EC REMAP MINIMUM PDOS</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=EtherCAT:EC_REMAP_MINIMUM_PDOS&amp;diff=125788"/>
				<updated>2016-02-28T10:37:04Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:EtherCAT-Function&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
This subroutine remaps the PDO's of a certain drive to the required minimum objects that allow sync position mode.&lt;br /&gt;
These objects are:&lt;br /&gt;
Rx - Control Word 0x6040;0x0, Position Command 0x607A;0x0&lt;br /&gt;
Tx - Status Word 0x6041;0x0, Position Feedback 0x6064;0x0, Digital Inputs 0x60FD;0x0&lt;br /&gt;
&lt;br /&gt;
Use this subroutine when integrating a softMC with a new or unknown motion drive to make sure it has the required minimum PDO entries to allow sync position motion.&lt;br /&gt;
&lt;br /&gt;
{{Note|&lt;br /&gt;
Use this subroutine as an example how to create you own PDO mapping}}&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
This subroutine must be invoked before [[:Category:EtherCAT:EC SETUP|EC_SETUP.PRG]] is executed, or right at the beginning of it, to allow MC to first rescan the slaves and get updated with the new PDO mapping of the devices}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|INPUT=&lt;br /&gt;
Slave address&lt;br /&gt;
&lt;br /&gt;
|OUTPUT=&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
|RETURN VALUE=&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
|DECLARATION=&lt;br /&gt;
Public Sub EC_REMAP_MINIMUM_PDOS(byval drive_addr as long)&lt;br /&gt;
&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
call EC_REMAP_MINIMUM_PDOS(&amp;lt;Slave address&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
|EXAMPLE=&lt;br /&gt;
call EC_REMAP_MINIMUM_PDOS(2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
* [[:Category:EtherCAT:EC SETUP|Setup EtherCAT]] - How to setup EtherCAT&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=EtherCAT:EC_REMAP_MINIMUM_PDOS&amp;diff=125787</id>
		<title>EtherCAT:EC REMAP MINIMUM PDOS</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=EtherCAT:EC_REMAP_MINIMUM_PDOS&amp;diff=125787"/>
				<updated>2016-02-28T10:30:15Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: Created page with &amp;quot;{{Template:EtherCAT-Function  |DESCRIPTION= This subroutine remaps the PDO's of a certain drive to the required minimum objects that allow sync position mode.   {{Note/Importa...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:EtherCAT-Function&lt;br /&gt;
&lt;br /&gt;
|DESCRIPTION=&lt;br /&gt;
This subroutine remaps the PDO's of a certain drive to the required minimum objects that allow sync position mode.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
This subroutine must be invoked before [[:Category:EtherCAT:EC SETUP|EC_SETUP.PRG]] in executed, or right at the beginning of it, to allow MC to first rescan the slaves and get updated with the new PDO mapping of the devices}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|INPUT=&lt;br /&gt;
Motion cycle time: 4000 μs, 2000 μs, 1000 μs, 500 μs or 250 μs.&lt;br /&gt;
If 500 μs or 250 μs cycle time is chosen, add to /FFS0/FWCONFIG the line: hpetfreq = 2000&lt;br /&gt;
&lt;br /&gt;
|OUTPUT=&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
|RETURN VALUE=&lt;br /&gt;
None&lt;br /&gt;
&lt;br /&gt;
|DECLARATION=&lt;br /&gt;
public sub EC_SET_BUS_CYCLETIME(byval cycle_time as long)&lt;br /&gt;
&lt;br /&gt;
|SYNTAX=&lt;br /&gt;
call EC_SET_BUS_CYCLETIME(&amp;lt;cycle_time&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
|EXAMPLE=&lt;br /&gt;
call EC_SET_BUS_CYCLETIME(4000)&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|SEE ALSO=&lt;br /&gt;
* [[EtherCAT:EC_GET_BUS_CYCLETIME|EC_GET_BUS_CYCLETIME]]&lt;br /&gt;
* [[:Category:EtherCAT:EC SETUP|Setup EtherCAT]] - How to setup EtherCAT&lt;br /&gt;
&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125786</id>
		<title>Category:EtherCAT:EC SETUP</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125786"/>
				<updated>2016-02-28T10:10:17Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Category&lt;br /&gt;
|description=How to Set up EtherCAT.&lt;br /&gt;
|frontpage=[[EtherCAT]]&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
Before starting to work with the softMC, you must setup the EtherCAT master to work with the slaves.&amp;lt;br/&amp;gt;&lt;br /&gt;
You must configure the axes in the system in a certain manner, then invoke certain functions and subroutines in an orderly manner, and make sure no errors occur.&lt;br /&gt;
&lt;br /&gt;
A CONFIG.PRG and a program file EC_SETUP.PRG exist in the repository, and demonstrate the following process.&lt;br /&gt;
&lt;br /&gt;
CONFIG.PRG allocates an array of generic axes by the name Axes[], and sets all the existing axes in the system into this array.&amp;lt;br/&amp;gt;&lt;br /&gt;
{{Note| Since verison 0.4.15.3rc6 the global axis array systemAxis[] is introduced, and the array Axes[] is made redundant, therefore it is removed from CONFIG.PRG }}&lt;br /&gt;
EC_SETUP.PRG and AX_SETUP.PRG use this array to setup the system automatically.&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
It is critical to maintain the demonstrated order of the EtherCAT setup.&amp;lt;br/&amp;gt;Any change in the given example may result in undefined behavior!}}&lt;br /&gt;
&lt;br /&gt;
==EC_SETUP.PRG==&lt;br /&gt;
EC_SETUP.PRG is a generic script. Its purpose is to configure the EtherCAT master and slaves before they are started, start the master, and eventually run additional actions to complete the EtherCAT startup procedure.&lt;br /&gt;
&lt;br /&gt;
EC_SETUP.PRG is written in a manner that easily allows embedding code to configure specific motion drives and IO modules.&lt;br /&gt;
&lt;br /&gt;
This article details the main steps that occur upon EtherCAT startup as they are executed by EC_SETUP.PRG.&lt;br /&gt;
&lt;br /&gt;
==Drive Address==&lt;br /&gt;
Each EtherCAT slave has an address. Currently this address is determined strictly according to the slave location in the&lt;br /&gt;
[[:File:Axystems;EC_master_slave_position_topology.PNG|physical topology]] of the system; that is, the first slave attached to the MC is assigned drive address 1, the second slave in the chain gets slave address 2, and so on. &lt;br /&gt;
&lt;br /&gt;
An EtherCAT slave can be a motion drive or an IO module.&lt;br /&gt;
&lt;br /&gt;
==PRE-OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Before the master is started all the slaves are in PRE-OP mode. In this stage the master is created and the system gathers information from the slaves in order to create data structures that are used by the master to set up the EtherCAT communication.&lt;br /&gt;
&lt;br /&gt;
First, differentiate between '''motion drives''' and '''IO modules'''. For each slave query the slave's Vendor ID and Product Code.&lt;br /&gt;
This data can later be used to identify specific products and create specific configuration for them, as in the [[EtherCAT:EC_INSTALL_STX_CDHD|CDHD Configuration example]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	numOfSlaves = EC_ETHERCAT_INIT&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Look for an unknown generic DS402 motion drive. If found, remap its PDOs to the required minimum.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	for drive_addr = 1 to numOfSlaves&lt;br /&gt;
		if ETSLAVES[drive_addr]-&amp;gt;et_slavetype = ECAT_MOTIONSLAVE then&lt;br /&gt;
			if EC_SLAVES_INFO[drive_addr]-&amp;gt;vendor_id = GENERIC_DS402_DRIVE_VENDOR then&lt;br /&gt;
				call EC_REMAP_MINIMUM_PDOS(drive_addr)&lt;br /&gt;
			end if&lt;br /&gt;
		end if&lt;br /&gt;
	next&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Check the EtherCAT Topology for Wiring Errors===&lt;br /&gt;
EtherCAT topology is sensitive to the direction of the wiring. Each EtherCAT slave has an INPUT connector and an OUTPUT connector.&amp;lt;br/&amp;gt;&lt;br /&gt;
The cable that &amp;quot;starts&amp;quot; from the EtherCAT master's OUTPUT must be connected to the INPUT of the first EtherCAT slave. A second cable will &amp;quot;exit&amp;quot; from the OUTPUT of the first slave and get connected to the INPUT of the second slave, etc...&amp;lt;br/&amp;gt;&lt;br /&gt;
'Miswiring' on most occasions means that somewhere in the topology the EtherCAT cable wiring got confused between the INPUT and the OUTPUT connectors.&amp;lt;br/&amp;gt;&lt;br /&gt;
This situation results UNDEFINED behavior, even up to making the wrong motor move, which is a safety issue.&lt;br /&gt;
{{Note/Important|If a miswiring is detected, an error will be thrown and EC_SETUP.PRG will stop running}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	retVal = CHECK_TOPOLOGY&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create the EtherCAT Master.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_CREATE_MASTER&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set Motion Cycle Time: 4000, 2000, 1000, 500 or 250 [us]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_SET_BUS_CYCLETIME(4000)  ' For a cycle time of 500/250[us], add to FWCONFIG: hpetfreq = 2000&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
From here on EC_SETUP.PRG uses the gathered information to configure the slaves. A 'For Loop' goes over the slaves and tries to match&lt;br /&gt;
them to already known products (such as the CDHD). When found, product specific functions are invoked to create data structures in the master that elaborate the PDO mapping of the slaves, be it a motion drive or an IO module. This is where you can add your own code to configure your own EtherCAT slave. Just add another case to match your Vendor ID.&lt;br /&gt;
&lt;br /&gt;
If a Servotronix (STX) CDHD servo motion drive is found, the function [[EtherCAT:EC_INSTALL_STX_CDHD|EC_INSTALL_STX_CDHD]] is invoked. This function sets certain parameters in the drive, creates the PDO map of the CDHD, and queries the drive's PNUM and PDEN to allow calculation of the [[MC-Basic:axis.POSITIONFACTOR|Position Factor]].&lt;br /&gt;
&lt;br /&gt;
For a generic drive, a minimum PDO mapping and default values are used. &lt;br /&gt;
&lt;br /&gt;
The user can add his own code to [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]] to perform any specific configuration that must take place while the slaves are in PREOP mode.&lt;br /&gt;
&lt;br /&gt;
After the slave configuration is done, a few more subroutines are called sequentially to complete the master's preparation,&lt;br /&gt;
and the master is started:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_ASSIGN_PDOS_AUTO&lt;br /&gt;
&lt;br /&gt;
	' After telling the master which slaves we want to work with, we create the PDO map&lt;br /&gt;
	call EC_CREATE_PDOS_MAP&lt;br /&gt;
&lt;br /&gt;
	call EC_SET_CYCLETIME  ' Set EtherCAT cycle time&lt;br /&gt;
&lt;br /&gt;
	' Raise slaves to OP-Mode&lt;br /&gt;
	call EC_STARTMASTER  ' Syncs clocks between the master and the slaves, and sets master's opmode to operational&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The master attempts to raise all the slaves to OP Mode. If it fails, the procedure is stopped and an error is issued.&lt;br /&gt;
If it is successful, EtherCAT communication is now online and EC_SETUP.PRG starts the second stage of configuration.&lt;br /&gt;
&lt;br /&gt;
==OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Again, a For Loop goes over all the slaves. When a motion drive is encountered, EC_SETUP.PRG attaches its drive address to an axis and&lt;br /&gt;
attempts to clear its faults.&lt;br /&gt;
Again, the user can add his own code to [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]] and [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]] to perform any specific configuration that must take place while the slaves are in &amp;quot;SAFEOP&amp;quot; or &amp;quot;OP&amp;quot; mode.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' SAFEOP state configuration - Add code to EC_USER_SAFEOP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_SAFEOP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' OP state configuration - Add code to EC_USER_OP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_OP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' Assign slave address to an axis&lt;br /&gt;
	Axes[Axis_Attached_To_Drive].dadd = drive_addr&lt;br /&gt;
&lt;br /&gt;
	' Attempt to clear faults in the drives&lt;br /&gt;
	Try&lt;br /&gt;
&lt;br /&gt;
		call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	Catch Else&lt;br /&gt;
&lt;br /&gt;
		' if clear faults failed due to PLL Sync Error, wait a little longer and retry&lt;br /&gt;
		if EC_SDO_READ(drive_addr, 0x603f, 0) = 0x7386 then&lt;br /&gt;
			printu &amp;quot;PLL Error in drive #. Sleeping 5 seconds and retrying to clear fault&amp;quot;;drive_addr&lt;br /&gt;
			sleep 5000&lt;br /&gt;
			call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
		end if&lt;br /&gt;
&lt;br /&gt;
	End Try&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
All the motion drives are set to Synchronous Position Mode:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' Set drives to sync position mode&lt;br /&gt;
	if EC_IS_PDO(Axes[Axis_Attached_To_Drive].dadd, 0x6060, 0) then&lt;br /&gt;
		call EC_PDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8)&lt;br /&gt;
	else&lt;br /&gt;
		call EC_SDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8, 8)&lt;br /&gt;
	end if&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
* [[EtherCAT:EC ETHERCAT INIT|EC_ETHERCAT_INIT]]&lt;br /&gt;
* [[EtherCAT:EC REMAP MINIMUM PDOS|EC_REMAP_MINIMUM_PDOS]]&lt;br /&gt;
* [[EtherCAT:EC CREATE MASTER|EC_CREATE_MASTER]]&lt;br /&gt;
* [[EtherCAT:EC SET BUS CYCLETIME|EC_SET_BUS_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC ASSIGN PDOS AUTO|EC_ASSIGN_PDOS_AUTO]]&lt;br /&gt;
* [[EtherCAT:EC CREATE PDOS MAP|EC_CREATE_PDOS_MAP]]&lt;br /&gt;
* [[EtherCAT:EC SET CYCLETIME|EC_SET_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC STARTMASTER|EC_STARTMASTER]]&lt;br /&gt;
* [[EtherCAT:EC CLEAR FAULTS|EC_CLEAR_FAULTS]]&lt;br /&gt;
* [[EtherCAT:EC SDO READ|EC_SDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC SDO WRITE|EC_SDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC PDO READ|EC_PDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC PDO WRITE|EC_PDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC IS PDO|EC_IS_PDO]]&lt;br /&gt;
* [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
[[Category:EtherCAT]]&lt;br /&gt;
[[Category:Control:Offline]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125785</id>
		<title>Category:EtherCAT:EC SETUP</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Category:EtherCAT:EC_SETUP&amp;diff=125785"/>
				<updated>2016-02-28T10:09:40Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Category&lt;br /&gt;
|description=How to Set up EtherCAT.&lt;br /&gt;
|frontpage=[[EtherCAT]]&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
Before starting to work with the softMC, you must setup the EtherCAT master to work with the slaves.&amp;lt;br/&amp;gt;&lt;br /&gt;
You must configure the axes in the system in a certain manner, then invoke certain functions and subroutines in an orderly manner, and make sure no errors occur.&lt;br /&gt;
&lt;br /&gt;
A CONFIG.PRG and a program file EC_SETUP.PRG exist in the repository, and demonstrate the following process.&lt;br /&gt;
&lt;br /&gt;
CONFIG.PRG allocates an array of generic axes by the name Axes[], and sets all the existing axes in the system into this array.&amp;lt;br/&amp;gt;&lt;br /&gt;
{{Note| Since verison 0.4.15.3rc6 the global axis array systemAxis[] is introduced, and the array Axes is made redundant, therefore it is removed from CONFIG.PRG }}&lt;br /&gt;
EC_SETUP.PRG and AX_SETUP.PRG use this array to setup the system automatically.&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|&lt;br /&gt;
It is critical to maintain the demonstrated order of the EtherCAT setup.&amp;lt;br/&amp;gt;Any change in the given example may result in undefined behavior!}}&lt;br /&gt;
&lt;br /&gt;
==EC_SETUP.PRG==&lt;br /&gt;
EC_SETUP.PRG is a generic script. Its purpose is to configure the EtherCAT master and slaves before they are started, start the master, and eventually run additional actions to complete the EtherCAT startup procedure.&lt;br /&gt;
&lt;br /&gt;
EC_SETUP.PRG is written in a manner that easily allows embedding code to configure specific motion drives and IO modules.&lt;br /&gt;
&lt;br /&gt;
This article details the main steps that occur upon EtherCAT startup as they are executed by EC_SETUP.PRG.&lt;br /&gt;
&lt;br /&gt;
==Drive Address==&lt;br /&gt;
Each EtherCAT slave has an address. Currently this address is determined strictly according to the slave location in the&lt;br /&gt;
[[:File:Axystems;EC_master_slave_position_topology.PNG|physical topology]] of the system; that is, the first slave attached to the MC is assigned drive address 1, the second slave in the chain gets slave address 2, and so on. &lt;br /&gt;
&lt;br /&gt;
An EtherCAT slave can be a motion drive or an IO module.&lt;br /&gt;
&lt;br /&gt;
==PRE-OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Before the master is started all the slaves are in PRE-OP mode. In this stage the master is created and the system gathers information from the slaves in order to create data structures that are used by the master to set up the EtherCAT communication.&lt;br /&gt;
&lt;br /&gt;
First, differentiate between '''motion drives''' and '''IO modules'''. For each slave query the slave's Vendor ID and Product Code.&lt;br /&gt;
This data can later be used to identify specific products and create specific configuration for them, as in the [[EtherCAT:EC_INSTALL_STX_CDHD|CDHD Configuration example]].&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	numOfSlaves = EC_ETHERCAT_INIT&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Look for an unknown generic DS402 motion drive. If found, remap its PDOs to the required minimum.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	for drive_addr = 1 to numOfSlaves&lt;br /&gt;
		if ETSLAVES[drive_addr]-&amp;gt;et_slavetype = ECAT_MOTIONSLAVE then&lt;br /&gt;
			if EC_SLAVES_INFO[drive_addr]-&amp;gt;vendor_id = GENERIC_DS402_DRIVE_VENDOR then&lt;br /&gt;
				call EC_REMAP_MINIMUM_PDOS(drive_addr)&lt;br /&gt;
			end if&lt;br /&gt;
		end if&lt;br /&gt;
	next&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Check the EtherCAT Topology for Wiring Errors===&lt;br /&gt;
EtherCAT topology is sensitive to the direction of the wiring. Each EtherCAT slave has an INPUT connector and an OUTPUT connector.&amp;lt;br/&amp;gt;&lt;br /&gt;
The cable that &amp;quot;starts&amp;quot; from the EtherCAT master's OUTPUT must be connected to the INPUT of the first EtherCAT slave. A second cable will &amp;quot;exit&amp;quot; from the OUTPUT of the first slave and get connected to the INPUT of the second slave, etc...&amp;lt;br/&amp;gt;&lt;br /&gt;
'Miswiring' on most occasions means that somewhere in the topology the EtherCAT cable wiring got confused between the INPUT and the OUTPUT connectors.&amp;lt;br/&amp;gt;&lt;br /&gt;
This situation results UNDEFINED behavior, even up to making the wrong motor move, which is a safety issue.&lt;br /&gt;
{{Note/Important|If a miswiring is detected, an error will be thrown and EC_SETUP.PRG will stop running}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	retVal = CHECK_TOPOLOGY&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create the EtherCAT Master.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_CREATE_MASTER&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set Motion Cycle Time: 4000, 2000, 1000, 500 or 250 [us]&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_SET_BUS_CYCLETIME(4000)  ' For a cycle time of 500/250[us], add to FWCONFIG: hpetfreq = 2000&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
From here on EC_SETUP.PRG uses the gathered information to configure the slaves. A 'For Loop' goes over the slaves and tries to match&lt;br /&gt;
them to already known products (such as the CDHD). When found, product specific functions are invoked to create data structures in the master that elaborate the PDO mapping of the slaves, be it a motion drive or an IO module. This is where you can add your own code to configure your own EtherCAT slave. Just add another case to match your Vendor ID.&lt;br /&gt;
&lt;br /&gt;
If a Servotronix (STX) CDHD servo motion drive is found, the function [[EtherCAT:EC_INSTALL_STX_CDHD|EC_INSTALL_STX_CDHD]] is invoked. This function sets certain parameters in the drive, creates the PDO map of the CDHD, and queries the drive's PNUM and PDEN to allow calculation of the [[MC-Basic:axis.POSITIONFACTOR|Position Factor]].&lt;br /&gt;
&lt;br /&gt;
For a generic drive, a minimum PDO mapping and default values are used. &lt;br /&gt;
&lt;br /&gt;
The user can add his own code to [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]] to perform any specific configuration that must take place while the slaves are in PREOP mode.&lt;br /&gt;
&lt;br /&gt;
After the slave configuration is done, a few more subroutines are called sequentially to complete the master's preparation,&lt;br /&gt;
and the master is started:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	call EC_ASSIGN_PDOS_AUTO&lt;br /&gt;
&lt;br /&gt;
	' After telling the master which slaves we want to work with, we create the PDO map&lt;br /&gt;
	call EC_CREATE_PDOS_MAP&lt;br /&gt;
&lt;br /&gt;
	call EC_SET_CYCLETIME  ' Set EtherCAT cycle time&lt;br /&gt;
&lt;br /&gt;
	' Raise slaves to OP-Mode&lt;br /&gt;
	call EC_STARTMASTER  ' Syncs clocks between the master and the slaves, and sets master's opmode to operational&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The master attempts to raise all the slaves to OP Mode. If it fails, the procedure is stopped and an error is issued.&lt;br /&gt;
If it is successful, EtherCAT communication is now online and EC_SETUP.PRG starts the second stage of configuration.&lt;br /&gt;
&lt;br /&gt;
==OP Mode ==&lt;br /&gt;
&lt;br /&gt;
Again, a For Loop goes over all the slaves. When a motion drive is encountered, EC_SETUP.PRG attaches its drive address to an axis and&lt;br /&gt;
attempts to clear its faults.&lt;br /&gt;
Again, the user can add his own code to [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]] and [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]] to perform any specific configuration that must take place while the slaves are in &amp;quot;SAFEOP&amp;quot; or &amp;quot;OP&amp;quot; mode.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' SAFEOP state configuration - Add code to EC_USER_SAFEOP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_SAFEOP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' OP state configuration - Add code to EC_USER_OP_CONFIG(byval drive_addr as long)&lt;br /&gt;
	retVal = EC_USER_OP_CONFIG(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	' Assign slave address to an axis&lt;br /&gt;
	Axes[Axis_Attached_To_Drive].dadd = drive_addr&lt;br /&gt;
&lt;br /&gt;
	' Attempt to clear faults in the drives&lt;br /&gt;
	Try&lt;br /&gt;
&lt;br /&gt;
		call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
&lt;br /&gt;
	Catch Else&lt;br /&gt;
&lt;br /&gt;
		' if clear faults failed due to PLL Sync Error, wait a little longer and retry&lt;br /&gt;
		if EC_SDO_READ(drive_addr, 0x603f, 0) = 0x7386 then&lt;br /&gt;
			printu &amp;quot;PLL Error in drive #. Sleeping 5 seconds and retrying to clear fault&amp;quot;;drive_addr&lt;br /&gt;
			sleep 5000&lt;br /&gt;
			call EC_CLEAR_FAULTS(drive_addr)&lt;br /&gt;
		end if&lt;br /&gt;
&lt;br /&gt;
	End Try&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
All the motion drives are set to Synchronous Position Mode:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
	' Set drives to sync position mode&lt;br /&gt;
	if EC_IS_PDO(Axes[Axis_Attached_To_Drive].dadd, 0x6060, 0) then&lt;br /&gt;
		call EC_PDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8)&lt;br /&gt;
	else&lt;br /&gt;
		call EC_SDO_WRITE(Axes[Axis_Attached_To_Drive].dadd, Modes_Of_Operation_6060h, 0, 8, 8)&lt;br /&gt;
	end if&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
* [[EtherCAT:EC ETHERCAT INIT|EC_ETHERCAT_INIT]]&lt;br /&gt;
* [[EtherCAT:EC REMAP MINIMUM PDOS|EC_REMAP_MINIMUM_PDOS]]&lt;br /&gt;
* [[EtherCAT:EC CREATE MASTER|EC_CREATE_MASTER]]&lt;br /&gt;
* [[EtherCAT:EC SET BUS CYCLETIME|EC_SET_BUS_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC ASSIGN PDOS AUTO|EC_ASSIGN_PDOS_AUTO]]&lt;br /&gt;
* [[EtherCAT:EC CREATE PDOS MAP|EC_CREATE_PDOS_MAP]]&lt;br /&gt;
* [[EtherCAT:EC SET CYCLETIME|EC_SET_CYCLETIME]]&lt;br /&gt;
* [[EtherCAT:EC STARTMASTER|EC_STARTMASTER]]&lt;br /&gt;
* [[EtherCAT:EC CLEAR FAULTS|EC_CLEAR_FAULTS]]&lt;br /&gt;
* [[EtherCAT:EC SDO READ|EC_SDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC SDO WRITE|EC_SDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC PDO READ|EC_PDO_READ]]&lt;br /&gt;
* [[EtherCAT:EC PDO WRITE|EC_PDO_WRITE]]&lt;br /&gt;
* [[EtherCAT:EC IS PDO|EC_IS_PDO]]&lt;br /&gt;
* [[EtherCAT:EC_USER_PREOP_CONFIG|EC_USER_PREOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_SAFEOP_CONFIG|EC_USER_SAFEOP_CONFIG]]&lt;br /&gt;
* [[EtherCAT:EC_USER_OP_CONFIG|EC_USER_OP_CONFIG]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
[[Category:EtherCAT]]&lt;br /&gt;
[[Category:Control:Offline]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=File:MB_x86_Object.ZIP&amp;diff=125771</id>
		<title>File:MB x86 Object.ZIP</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=File:MB_x86_Object.ZIP&amp;diff=125771"/>
				<updated>2016-02-25T10:19:41Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: Nigeller uploaded a new version of &amp;amp;quot;File:MB x86 Object.ZIP&amp;amp;quot;: ModBus object compiled for x86 platform&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ModBus object compiled for x86 platform&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=File:MB_x86_Object.ZIP&amp;diff=125770</id>
		<title>File:MB x86 Object.ZIP</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=File:MB_x86_Object.ZIP&amp;diff=125770"/>
				<updated>2016-02-25T10:16:26Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: ModBus object compiled for x86 platform
-&amp;gt; Creation failed: Unsupported filetype!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ModBus object compiled for x86 platform&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=File:MB_ARM_Object.ZIP&amp;diff=125768</id>
		<title>File:MB ARM Object.ZIP</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=File:MB_ARM_Object.ZIP&amp;diff=125768"/>
				<updated>2016-02-25T09:46:33Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: ARM compiation of ModBus object
-&amp;gt; Creation failed: Unsupported filetype!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ARM compiation of ModBus object&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Program_Examples:TCP_IP:TCPIP_Simple_Client&amp;diff=125738</id>
		<title>Program Examples:TCP IP:TCPIP Simple Client</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Program_Examples:TCP_IP:TCPIP_Simple_Client&amp;diff=125738"/>
				<updated>2016-01-03T07:19:11Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The following example demonstrates the set up of a simple TCP-IP client.&lt;br /&gt;
&lt;br /&gt;
The client opens a socket and tries to connect. The server must be blocked on accept for &amp;quot;connect&amp;quot; to be successful. Then an exchange of messages takes place and the client closes the connection and terminates.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
program&lt;br /&gt;
&lt;br /&gt;
Dim str1 as string&lt;br /&gt;
Dim Test_str1 as string&lt;br /&gt;
Dim Test_str2 as string&lt;br /&gt;
&lt;br /&gt;
	Try&lt;br /&gt;
		OpenSocket Options=1 as #3&lt;br /&gt;
	catch 5043 'socket is already open&lt;br /&gt;
		print &amp;quot;socket 3 is already open. Closing and reopening&amp;quot;&lt;br /&gt;
		close #3&lt;br /&gt;
		OpenSocket Options=1 as #3&lt;br /&gt;
	End Try&lt;br /&gt;
&lt;br /&gt;
	Test_str1=&amp;quot;Client sending &amp;quot;&lt;br /&gt;
	Test_str2=&amp;quot;test string&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	Connect(#3, &amp;quot;10.4.20.214&amp;quot;, 6001)&lt;br /&gt;
&lt;br /&gt;
	sleep 200&lt;br /&gt;
	print #3, Test_str1;Test_str2; 'send&lt;br /&gt;
	sleep 200&lt;br /&gt;
	str1=input$(loc(3),#3) 'receive&lt;br /&gt;
&lt;br /&gt;
	if str1=&amp;quot;Server sending test string&amp;quot; then&lt;br /&gt;
		?&amp;quot;client.prg test is successful&amp;quot;&lt;br /&gt;
	else&lt;br /&gt;
		?&amp;quot;client.prg test FAILED&amp;quot;&lt;br /&gt;
		?str1 , len(str1)&lt;br /&gt;
	end if&lt;br /&gt;
&lt;br /&gt;
	sleep 200&lt;br /&gt;
&lt;br /&gt;
	close #3&lt;br /&gt;
	Print &amp;quot;Client Closed Socket. Client Exits&amp;quot;&lt;br /&gt;
&lt;br /&gt;
end program&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The example corresponds to commit SHA-1: ada143a7f402e6bbad24c13c56401a5393ce3d2b in GIT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
* [[Program Examples:TCP IP:TCPIP Simple Server|TCP/IP Simple Server]]&lt;br /&gt;
* [[Program Examples:TCP IP:TCPIP Multi Server|TCP/IP Multi Clients Server]]&lt;br /&gt;
* [[Program_Examples:TCP_IP:TCPIP_TelNet_Server|TCP/IP TelNet Server]]&lt;br /&gt;
* [[Program_Examples:TCP_IP:TCPIP_Winsock_Client|TCP/IP windows socket client]]&lt;br /&gt;
* [[MC-Basic:ACCEPT|ACCEPT]]&lt;br /&gt;
* [[MC-Basic:CLOSE|CLOSE]]&lt;br /&gt;
* [[MC-Basic:CONNECT|CONNECT]]&lt;br /&gt;
* [[MC-Basic:OPENSOCKET|OPENSOCKET]]&lt;br /&gt;
* [[MC-Basic:INPUT$|INPUT$]]&lt;br /&gt;
* [[MC-Basic:PING|PING]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Program_Examples:Shared_Objects&amp;diff=125705</id>
		<title>Program Examples:Shared Objects</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Program_Examples:Shared_Objects&amp;diff=125705"/>
				<updated>2015-12-09T10:52:12Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The following example demonstrates how to compile a shared object in Linux and link it with softMC at run-time.&lt;br /&gt;
&lt;br /&gt;
Below there are 5 example files: A C source file, a C header file, a CPP source file, a CPP header file and a makefile.&amp;lt;br/&amp;gt;&lt;br /&gt;
The source and header files implement a simple program that is given 2 integers as arguments and returns their sum or difference.&amp;lt;br/&amp;gt;&lt;br /&gt;
This program DOESN'T include a main function, therefore the program can be compiled only into a library, and not an executable.&lt;br /&gt;
&lt;br /&gt;
==Example Program==&lt;br /&gt;
C Source file: Example.c&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;Example.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
/**************************    Linux sys.log Declarations    ******************************/&lt;br /&gt;
&lt;br /&gt;
/* MC Modules */&lt;br /&gt;
#define MODULE_NON	 	 0&lt;br /&gt;
#define MODULE_MOTION		 1&lt;br /&gt;
#define MODULE_RTS		 2&lt;br /&gt;
#define MODULE_TRANSLAT		 3&lt;br /&gt;
#define MODULE_SERCOS		 4&lt;br /&gt;
#define MODULE_ROBOT		 5&lt;br /&gt;
#define MODULE_TRACER		 6&lt;br /&gt;
#define MODULE_SYSTEM		 7&lt;br /&gt;
#define MODULE_MEMORY		 8&lt;br /&gt;
#define MODULE_FILE_SYSTEM	 9&lt;br /&gt;
#define MODULE_CLI		10&lt;br /&gt;
#define MODULE_RBOOTP		11&lt;br /&gt;
#define MODULE_ETHERCAT		12&lt;br /&gt;
#define MODULE_FASTDATA		13&lt;br /&gt;
#define MODULE_UAC		14&lt;br /&gt;
#define MODULE_MC_BASIC		15&lt;br /&gt;
#define MODULE_CANOPEN		16&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* MC Log Level */&lt;br /&gt;
#define LOG_LEVEL_NON		0&lt;br /&gt;
#define LOG_LEVEL_ERROR		1&lt;br /&gt;
#define LOG_LEVEL_WARNING	2&lt;br /&gt;
#define LOG_LEVEL_NOTE		3&lt;br /&gt;
#define LOG_LEVEL_DEBUG		4&lt;br /&gt;
#define LOG_LEVEL_ALL		5&lt;br /&gt;
&lt;br /&gt;
extern int sys_log(int sub_system, int _debug_level, const char * fmt, int arg1, int arg2,&lt;br /&gt;
			int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10);&lt;br /&gt;
&lt;br /&gt;
/******************************************************************************************/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int SHARED_OBJECT_SUM(int arg1, int arg2)&lt;br /&gt;
{&lt;br /&gt;
	sys_log(MODULE_NON, LOG_LEVEL_ERROR, &amp;quot;%s: arg1 = %d, arg2 = %d\n&amp;quot;, (int)__FUNCTION__, arg1, arg2, 0,0,0,0,0,0,0);&lt;br /&gt;
	print_hello();&lt;br /&gt;
&lt;br /&gt;
	return arg1 + arg2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void print_hello(void)&lt;br /&gt;
{&lt;br /&gt;
	fprintf(stderr, &amp;quot;Hello! This is just an example\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
C Header file: Example.h&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void print_hello(void);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CPP Source file: CPP_Example.c&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;CPP_Example.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
extern &amp;quot;C&amp;quot; {&lt;br /&gt;
&lt;br /&gt;
int SHARED_OBJECT_SUB(int arg1, int arg2)&lt;br /&gt;
{&lt;br /&gt;
	print_hello_cpp();&lt;br /&gt;
&lt;br /&gt;
	return arg1 - arg2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
} // extern &amp;quot;C&amp;quot; {&lt;br /&gt;
&lt;br /&gt;
void print_hello_cpp(void)&lt;br /&gt;
{&lt;br /&gt;
	std::cerr &amp;lt;&amp;lt; &amp;quot;A cpp example&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CPP Header file: CPP_Example.h&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void print_hello_cpp(void);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{Note/Important|When declaring function names that will be used from MC-Basic context you must use UPPERCASE letters, as in the example of SHARED_OBJECT_SUM and SHARED_OBJECT_SUB.&amp;lt;br/&amp;gt;User functions must be wrapped with extern &amp;quot;C&amp;quot; to avoid CPP mangled names}}&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
Output strings of functions like printf and fprintf are usually displayed in the Linux terminal, however in the softMC case the behavior is different.&amp;lt;br/&amp;gt;&lt;br /&gt;
The outputs of printf and cout are discarded while output strings of fprintf and cerr are directed to an object called 'nohup' and can later be read by the user.&amp;lt;br/&amp;gt;&lt;br /&gt;
To display the contents of nohup do the following:&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
1. Connect to the softMC using ssh or serial console.&amp;lt;br/&amp;gt;&lt;br /&gt;
2. In the Linux terminal type:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-bash-3.2$ cat /var/home/mc/nohup.out&lt;br /&gt;
....&lt;br /&gt;
....&lt;br /&gt;
Hello! This is just an example&lt;br /&gt;
A cpp example&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
== Getting Compiler ==&lt;br /&gt;
The compiler and linker shall be used in order to build the shared object is defined by the CC variable in the makefile.&amp;lt;br/&amp;gt;&lt;br /&gt;
You would need any linux installation (like Ubuntu) in order to run softMC compiler.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cut and Paste following commands to Linux command line:&amp;lt;br/&amp;gt;&lt;br /&gt;
cd ~&amp;lt;br/&amp;gt;&lt;br /&gt;
wget --no-check-certificate http://servotronix.com/html/softMC_Tool_Chain/0B-jc7OYLo3AYaGFfN2ZkTUNJdHM.tar&amp;lt;br /&amp;gt;&lt;br /&gt;
tar -zxvf 0B-jc7OYLo3AYaGFfN2ZkTUNJdHM.tar&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Complete softMC tool-chain will be installed into your home directory at ~/OSELAS.Toolchain-2011.03.1&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you are working on a 64 bits Linux, install the following packages:&lt;br /&gt;
&lt;br /&gt;
sudo apt-get install libc6-i386&amp;lt;br/&amp;gt;&lt;br /&gt;
sudo apt-get install zlib1g:i386&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Makefile==&lt;br /&gt;
Please notice that makefle CC variable is assigned with a complete path to gcc compiler. This specific gcc is a part of the tool chain we use to build softMC.&lt;br /&gt;
When compiling shared objects to be linked with softMC it is advised to use OSELAS.Toolchain-2011.03.1 tool chain.&amp;lt;br/&amp;gt;&lt;br /&gt;
The CFLAGS and CPPFLAGS variables in the example might cause compilation errors. It is not advised, but you can remove those that prevent a successful compilation.&lt;br /&gt;
The better option is to fix the compilation errors.&lt;br /&gt;
&lt;br /&gt;
The makefile syntax:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
CC=~/OSELAS.Toolchain-2011.03.1/i586-unknown-linux-gnu/gcc-4.5.2-glibc-2.13-binutils-2.21-kernel-2.6.36-sanitized/bin/i586-unknown-linux-gnu-gcc&lt;br /&gt;
CXX=~/OSELAS.Toolchain-2011.03.1/i586-unknown-linux-gnu/gcc-4.5.2-glibc-2.13-binutils-2.21-kernel-2.6.36-sanitized/bin/i586-unknown-linux-gnu-g++&lt;br /&gt;
CFLAGS=-c -g -ansi -pedantic -Wall -Werror&lt;br /&gt;
CPPFLAGS=-c -g -ansi -pedantic -Wall -Werror&lt;br /&gt;
&lt;br /&gt;
LD_LIBRARY_PATH := .:$(LD_LIBRARY_PATH)&lt;br /&gt;
&lt;br /&gt;
C_SOURCE=Example.c&lt;br /&gt;
CPP_SOURCE=CPP_Example.cpp&lt;br /&gt;
&lt;br /&gt;
C_OBJECTS=$(C_SOURCE:.c=.o)&lt;br /&gt;
CPP_OBJECTS=$(CPP_SOURCE:.cpp=.o)&lt;br /&gt;
&lt;br /&gt;
TARGET=EXAMPLE.O&lt;br /&gt;
&lt;br /&gt;
$(TARGET): $(C_OBJECTS) $(CPP_OBJECTS)&lt;br /&gt;
	$(CC) -shared -o $@ $(C_OBJECTS) $(CPP_OBJECTS)&lt;br /&gt;
&lt;br /&gt;
$(C_OBJECTS): $(C_SOURCE)&lt;br /&gt;
	$(CC) $(CFLAGS) -c $(C_SOURCE)&lt;br /&gt;
&lt;br /&gt;
$(CPP_OBJECTS): $(CPP_SOURCE)&lt;br /&gt;
	$(CXX) $(CPPFLAGS) -c $(CPP_SOURCE)&lt;br /&gt;
&lt;br /&gt;
clean:&lt;br /&gt;
	rm $(C_OBJECTS) $(CPP_OBJECTS) $(TARGET)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order to adapt the makefile to your needs, please change the assignment of the variables 'C_SOURCE' and 'CPP_SOURCE' to the name of the source files in your project, and the assignment of the variable 'TARGET'.&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|softMC can handle only UPPERCASE file names limited to 8.3 convention, meaning, up to 8 characters, followed by a dot, followed by the extensions PRG, or LIB or O (of course in our case it will be .O)&amp;lt;br/&amp;gt;Bear that in mind when assigning the TARGET variable}}&lt;br /&gt;
&lt;br /&gt;
After a successful compilation you will find in the working directory the file EXAMPLE.O, or whatever string was assigned to the variable 'TARGET'.&lt;br /&gt;
&lt;br /&gt;
==copy the shared object to softMC==&lt;br /&gt;
You can copy the shared object to softMC in 2 different ways:&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using scp, copy the file directly to softMC.&amp;lt;br/&amp;gt;&lt;br /&gt;
In the Linux terminal type:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
my_user@my_computer:~/working_directory$ scp EXAMPLE.O mc@mc.ip.add.ress:/FFS0/SSMC&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Where mc.ip.add.ress is the sfotMC's ip address, for example, 192.168.7.152.&amp;lt;br/&amp;gt;&lt;br /&gt;
or&amp;lt;br/&amp;gt;&lt;br /&gt;
2. Use the ControlStudio's file manager to drag and drop the file EXAMPLE.O to the softMC.&lt;br /&gt;
&lt;br /&gt;
==Link the shared object with softMC==&lt;br /&gt;
The shared object now resides within softMC. Now we want to link softMC with the shared object during run-time, and use it.&lt;br /&gt;
Linking the shared object is done with 'oload' command in CONFIG.PRG context.&lt;br /&gt;
Please add to your CONFIG.PRG the line:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
oload EXAMPLE.O&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we need to declare about the shared object's contents and how to use it. This is done by the PROTO.PRO file.&lt;br /&gt;
please add the following lines to your PROTO.PRO file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import_c SHARED_OBJECT_SUM(byval as long, byval as long) as long&lt;br /&gt;
import_c SHARED_OBJECT_SUB(byval as long, byval as long) as long&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Of course, 'SHARED_OBJECT_SUM' is a function implemented in Example.c. You will need to specify the prototypes of your own functions.&amp;lt;br/&amp;gt;&lt;br /&gt;
Using ControlStudio send the edited CONFIG.PRG and PROTO.PRO to softMC and type in the ControlStudio terminal 'reset all'.&lt;br /&gt;
&lt;br /&gt;
If the process was successful, you are now able to invoke functions from the shared object.&lt;br /&gt;
Type in the ControlStudio terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;?SHARED_OBJECT_SUM(5, 6)&lt;br /&gt;
11&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;?SHARED_OBJECT_SUB(5, 6)&lt;br /&gt;
-1&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Passing MC-Basic strings to C functions==&lt;br /&gt;
It is possible to send string objects to C functions for parsing purposes, for example. In order to do so you need to include in your code the following declarations:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
typedef int			INT32;&lt;br /&gt;
typedef unsigned int		UINT32;&lt;br /&gt;
typedef pthread_mutex_t*	SEMM_ID;&lt;br /&gt;
typedef int			FUNCPTR;	/* ptr to func returning int   */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* defining MC Basic SYS String */&lt;br /&gt;
typedef struct {&lt;br /&gt;
	INT32 type;				/* string type */&lt;br /&gt;
	INT32 scope;				/* string variable scope */&lt;br /&gt;
	INT32 temp;				/* memory release flag */&lt;br /&gt;
	INT32 alloc_size;			/* number of bytes allocated */&lt;br /&gt;
	INT32 occup_size;			/* number of bytes occupied */&lt;br /&gt;
	INT32 num_chars;			/* number of characters */&lt;br /&gt;
	UINT32 counter;				/* assignment counter */&lt;br /&gt;
	SEMM_ID mutex;				/* mutex */&lt;br /&gt;
	unsigned char* data;			/* pointer to string */&lt;br /&gt;
	FUNCPTR FuncUpdateString;		/* pointer to callback function */&lt;br /&gt;
	INT32 FuncUpdateStringParam;		/* parameter of callback function */&lt;br /&gt;
} SYS_STRING;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the declaration of the C function that receives the string, specify the string argument:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int MY_C_FUNCTION(int some_var, SYS_STRING* some_str)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In the import_c command that declares the interface from MC-Basic to C function, declare:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
import_c MY_C_FUNCTION(byval as long, byval as string) as long&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using Linux sys.log from Shared Object context==&lt;br /&gt;
It is possible to log messages in the Linux logger sys.log. In order to do so you need to include in your code the following declarations:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/**************************    Linux sys.log Declarations    ******************************/&lt;br /&gt;
&lt;br /&gt;
/* MC Modules */&lt;br /&gt;
#define MODULE_NON	 	 0&lt;br /&gt;
#define MODULE_MOTION		 1&lt;br /&gt;
#define MODULE_RTS		 2&lt;br /&gt;
#define MODULE_TRANSLAT		 3&lt;br /&gt;
#define MODULE_SERCOS		 4&lt;br /&gt;
#define MODULE_ROBOT		 5&lt;br /&gt;
#define MODULE_TRACER		 6&lt;br /&gt;
#define MODULE_SYSTEM		 7&lt;br /&gt;
#define MODULE_MEMORY		 8&lt;br /&gt;
#define MODULE_FILE_SYSTEM	 9&lt;br /&gt;
#define MODULE_CLI		10&lt;br /&gt;
#define MODULE_RBOOTP		11&lt;br /&gt;
#define MODULE_ETHERCAT		12&lt;br /&gt;
#define MODULE_FASTDATA		13&lt;br /&gt;
#define MODULE_UAC		14&lt;br /&gt;
#define MODULE_MC_BASIC		15&lt;br /&gt;
#define MODULE_CANOPEN		16&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* MC Log Level */&lt;br /&gt;
#define LOG_LEVEL_NON		0&lt;br /&gt;
#define LOG_LEVEL_ERROR		1&lt;br /&gt;
#define LOG_LEVEL_WARNING	2&lt;br /&gt;
#define LOG_LEVEL_NOTE		3&lt;br /&gt;
#define LOG_LEVEL_DEBUG		4&lt;br /&gt;
#define LOG_LEVEL_ALL		5&lt;br /&gt;
&lt;br /&gt;
extern int sys_log(int sub_system, int _debug_level, const char * fmt, int arg1, int arg2,&lt;br /&gt;
			int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10);&lt;br /&gt;
&lt;br /&gt;
/******************************************************************************************/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To send a message to sys.log invoke sys_log with fmt as a printf formatted string.&lt;br /&gt;
A more thorough explanation about sys.log and an example can be found in [[Program_Examples:sys_log|Linux sys.log]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
Extract Shared_Object.ZIP to find the above examples&amp;lt;br/&amp;gt;&lt;br /&gt;
[[File:Shared_Object.zip||Shared_Object.zip]]&lt;br /&gt;
&lt;br /&gt;
The example corresponds to commit SHA-1: 5228016ac44122213dcb05d781b15c8e05054d5b in GIT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
* [[MC-Basic_C-Interface|MC-Basic C-Interface]]&lt;br /&gt;
* [[MC-Basic:IMPORT_C|IMPORT_C]]&lt;br /&gt;
* [[Program_Examples:sys_log|Linux sys.log]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Program_Examples:Shared_Objects&amp;diff=125704</id>
		<title>Program Examples:Shared Objects</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Program_Examples:Shared_Objects&amp;diff=125704"/>
				<updated>2015-12-09T10:51:37Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The following example demonstrates how to compile a shared object in Linux and link it with softMC at run-time.&lt;br /&gt;
&lt;br /&gt;
Below there are 5 example files: A C source file, a C header file, a CPP source file, a CPP header file and a makefile.&amp;lt;br/&amp;gt;&lt;br /&gt;
The source and header files implement a simple program that is given 2 integers as arguments and returns their sum or difference.&amp;lt;br/&amp;gt;&lt;br /&gt;
This program DOESN'T include a main function, therefore the program can be compiled only into a library, and not an executable.&lt;br /&gt;
&lt;br /&gt;
==Example Program==&lt;br /&gt;
C Source file: Example.c&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;Example.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
/**************************    Linux sys.log Declarations    ******************************/&lt;br /&gt;
&lt;br /&gt;
/* MC Modules */&lt;br /&gt;
#define MODULE_NON	 	 0&lt;br /&gt;
#define MODULE_MOTION		 1&lt;br /&gt;
#define MODULE_RTS		 2&lt;br /&gt;
#define MODULE_TRANSLAT		 3&lt;br /&gt;
#define MODULE_SERCOS		 4&lt;br /&gt;
#define MODULE_ROBOT		 5&lt;br /&gt;
#define MODULE_TRACER		 6&lt;br /&gt;
#define MODULE_SYSTEM		 7&lt;br /&gt;
#define MODULE_MEMORY		 8&lt;br /&gt;
#define MODULE_FILE_SYSTEM	 9&lt;br /&gt;
#define MODULE_CLI		10&lt;br /&gt;
#define MODULE_RBOOTP		11&lt;br /&gt;
#define MODULE_ETHERCAT		12&lt;br /&gt;
#define MODULE_FASTDATA		13&lt;br /&gt;
#define MODULE_UAC		14&lt;br /&gt;
#define MODULE_MC_BASIC		15&lt;br /&gt;
#define MODULE_CANOPEN		16&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* MC Log Level */&lt;br /&gt;
#define LOG_LEVEL_NON		0&lt;br /&gt;
#define LOG_LEVEL_ERROR		1&lt;br /&gt;
#define LOG_LEVEL_WARNING	2&lt;br /&gt;
#define LOG_LEVEL_NOTE		3&lt;br /&gt;
#define LOG_LEVEL_DEBUG		4&lt;br /&gt;
#define LOG_LEVEL_ALL		5&lt;br /&gt;
&lt;br /&gt;
extern int sys_log(int sub_system, int _debug_level, const char * fmt, int arg1, int arg2,&lt;br /&gt;
			int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10);&lt;br /&gt;
&lt;br /&gt;
/******************************************************************************************/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int SHARED_OBJECT_SUM(int arg1, int arg2)&lt;br /&gt;
{&lt;br /&gt;
	sys_log(MODULE_NON, LOG_LEVEL_ERROR, &amp;quot;%s: arg1 = %d, arg2 = %d\n&amp;quot;, (int)__FUNCTION__, arg1, arg2, 0,0,0,0,0,0,0);&lt;br /&gt;
	print_hello();&lt;br /&gt;
&lt;br /&gt;
	return arg1 + arg2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void print_hello(void)&lt;br /&gt;
{&lt;br /&gt;
	fprintf(stderr, &amp;quot;Hello! This is just an example\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
C Header file: Example.h&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void print_hello(void);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CPP Source file: CPP_Example.c&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;CPP_Example.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
extern &amp;quot;C&amp;quot; {&lt;br /&gt;
&lt;br /&gt;
int SHARED_OBJECT_SUB(int arg1, int arg2)&lt;br /&gt;
{&lt;br /&gt;
	print_hello_cpp();&lt;br /&gt;
&lt;br /&gt;
	return arg1 - arg2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
} // extern &amp;quot;C&amp;quot; {&lt;br /&gt;
&lt;br /&gt;
void print_hello_cpp(void)&lt;br /&gt;
{&lt;br /&gt;
	std::cerr &amp;lt;&amp;lt; &amp;quot;A cpp example&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CPP Header file: CPP_Example.h&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void print_hello_cpp(void);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{Note/Important|When declaring function names that will be used from MC-Basic context you must use UPPERCASE letters, as in the example of SHARED_OBJECT_SUM and SHARED_OBJECT_SUB.&amp;lt;br/&amp;gt;User functions must be wrapped with extern &amp;quot;C&amp;quot; to avoid CPP mangled names}}&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
Output strings of functions like printf and fprintf are usually displayed in the Linux terminal, however in the softMC case the behavior is different.&amp;lt;br/&amp;gt;&lt;br /&gt;
The outputs of printf and cout are discarded while output strings of fprintf and cerr are directed to an object called 'nohup' and can later be read by the user.&amp;lt;br/&amp;gt;&lt;br /&gt;
To display the contents of nohup do the following:&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
1. Connect to the softMC using ssh or serial console.&amp;lt;br/&amp;gt;&lt;br /&gt;
2. In the Linux terminal type:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-bash-3.2$ cat /var/home/mc/nohup.out&lt;br /&gt;
....&lt;br /&gt;
....&lt;br /&gt;
Hello! This is just an example&lt;br /&gt;
A cpp example&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
== Getting Compiler ==&lt;br /&gt;
The compiler and linker shall be used in order to build the shared object is defined by the CC variable in the makefile.&amp;lt;br/&amp;gt;&lt;br /&gt;
You would need any linux installation (like Ubuntu) in order to run softMC compiler.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cut and Paste following commands to Linux command line:&amp;lt;br/&amp;gt;&lt;br /&gt;
cd ~&amp;lt;br/&amp;gt;&lt;br /&gt;
wget --no-check-certificate http://servotronix.com/html/softMC_Tool_Chain/0B-jc7OYLo3AYaGFfN2ZkTUNJdHM.tar&amp;lt;br /&amp;gt;&lt;br /&gt;
tar -zxvf 0B-jc7OYLo3AYaGFfN2ZkTUNJdHM.tar&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Complete softMC tool-chain will be installed into your home directory at ~/OSELAS.Toolchain-2011.03.1&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you are working on a 64 bits Linux, install the following packages:&lt;br /&gt;
&lt;br /&gt;
sudo apt-get install libc6-i386&lt;br /&gt;
sudo apt-get install zlib1g:i386&lt;br /&gt;
&lt;br /&gt;
==Makefile==&lt;br /&gt;
Please notice that makefle CC variable is assigned with a complete path to gcc compiler. This specific gcc is a part of the tool chain we use to build softMC.&lt;br /&gt;
When compiling shared objects to be linked with softMC it is advised to use OSELAS.Toolchain-2011.03.1 tool chain.&amp;lt;br/&amp;gt;&lt;br /&gt;
The CFLAGS and CPPFLAGS variables in the example might cause compilation errors. It is not advised, but you can remove those that prevent a successful compilation.&lt;br /&gt;
The better option is to fix the compilation errors.&lt;br /&gt;
&lt;br /&gt;
The makefile syntax:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
CC=~/OSELAS.Toolchain-2011.03.1/i586-unknown-linux-gnu/gcc-4.5.2-glibc-2.13-binutils-2.21-kernel-2.6.36-sanitized/bin/i586-unknown-linux-gnu-gcc&lt;br /&gt;
CXX=~/OSELAS.Toolchain-2011.03.1/i586-unknown-linux-gnu/gcc-4.5.2-glibc-2.13-binutils-2.21-kernel-2.6.36-sanitized/bin/i586-unknown-linux-gnu-g++&lt;br /&gt;
CFLAGS=-c -g -ansi -pedantic -Wall -Werror&lt;br /&gt;
CPPFLAGS=-c -g -ansi -pedantic -Wall -Werror&lt;br /&gt;
&lt;br /&gt;
LD_LIBRARY_PATH := .:$(LD_LIBRARY_PATH)&lt;br /&gt;
&lt;br /&gt;
C_SOURCE=Example.c&lt;br /&gt;
CPP_SOURCE=CPP_Example.cpp&lt;br /&gt;
&lt;br /&gt;
C_OBJECTS=$(C_SOURCE:.c=.o)&lt;br /&gt;
CPP_OBJECTS=$(CPP_SOURCE:.cpp=.o)&lt;br /&gt;
&lt;br /&gt;
TARGET=EXAMPLE.O&lt;br /&gt;
&lt;br /&gt;
$(TARGET): $(C_OBJECTS) $(CPP_OBJECTS)&lt;br /&gt;
	$(CC) -shared -o $@ $(C_OBJECTS) $(CPP_OBJECTS)&lt;br /&gt;
&lt;br /&gt;
$(C_OBJECTS): $(C_SOURCE)&lt;br /&gt;
	$(CC) $(CFLAGS) -c $(C_SOURCE)&lt;br /&gt;
&lt;br /&gt;
$(CPP_OBJECTS): $(CPP_SOURCE)&lt;br /&gt;
	$(CXX) $(CPPFLAGS) -c $(CPP_SOURCE)&lt;br /&gt;
&lt;br /&gt;
clean:&lt;br /&gt;
	rm $(C_OBJECTS) $(CPP_OBJECTS) $(TARGET)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order to adapt the makefile to your needs, please change the assignment of the variables 'C_SOURCE' and 'CPP_SOURCE' to the name of the source files in your project, and the assignment of the variable 'TARGET'.&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|softMC can handle only UPPERCASE file names limited to 8.3 convention, meaning, up to 8 characters, followed by a dot, followed by the extensions PRG, or LIB or O (of course in our case it will be .O)&amp;lt;br/&amp;gt;Bear that in mind when assigning the TARGET variable}}&lt;br /&gt;
&lt;br /&gt;
After a successful compilation you will find in the working directory the file EXAMPLE.O, or whatever string was assigned to the variable 'TARGET'.&lt;br /&gt;
&lt;br /&gt;
==copy the shared object to softMC==&lt;br /&gt;
You can copy the shared object to softMC in 2 different ways:&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using scp, copy the file directly to softMC.&amp;lt;br/&amp;gt;&lt;br /&gt;
In the Linux terminal type:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
my_user@my_computer:~/working_directory$ scp EXAMPLE.O mc@mc.ip.add.ress:/FFS0/SSMC&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Where mc.ip.add.ress is the sfotMC's ip address, for example, 192.168.7.152.&amp;lt;br/&amp;gt;&lt;br /&gt;
or&amp;lt;br/&amp;gt;&lt;br /&gt;
2. Use the ControlStudio's file manager to drag and drop the file EXAMPLE.O to the softMC.&lt;br /&gt;
&lt;br /&gt;
==Link the shared object with softMC==&lt;br /&gt;
The shared object now resides within softMC. Now we want to link softMC with the shared object during run-time, and use it.&lt;br /&gt;
Linking the shared object is done with 'oload' command in CONFIG.PRG context.&lt;br /&gt;
Please add to your CONFIG.PRG the line:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
oload EXAMPLE.O&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we need to declare about the shared object's contents and how to use it. This is done by the PROTO.PRO file.&lt;br /&gt;
please add the following lines to your PROTO.PRO file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import_c SHARED_OBJECT_SUM(byval as long, byval as long) as long&lt;br /&gt;
import_c SHARED_OBJECT_SUB(byval as long, byval as long) as long&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Of course, 'SHARED_OBJECT_SUM' is a function implemented in Example.c. You will need to specify the prototypes of your own functions.&amp;lt;br/&amp;gt;&lt;br /&gt;
Using ControlStudio send the edited CONFIG.PRG and PROTO.PRO to softMC and type in the ControlStudio terminal 'reset all'.&lt;br /&gt;
&lt;br /&gt;
If the process was successful, you are now able to invoke functions from the shared object.&lt;br /&gt;
Type in the ControlStudio terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;?SHARED_OBJECT_SUM(5, 6)&lt;br /&gt;
11&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;?SHARED_OBJECT_SUB(5, 6)&lt;br /&gt;
-1&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Passing MC-Basic strings to C functions==&lt;br /&gt;
It is possible to send string objects to C functions for parsing purposes, for example. In order to do so you need to include in your code the following declarations:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
typedef int			INT32;&lt;br /&gt;
typedef unsigned int		UINT32;&lt;br /&gt;
typedef pthread_mutex_t*	SEMM_ID;&lt;br /&gt;
typedef int			FUNCPTR;	/* ptr to func returning int   */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* defining MC Basic SYS String */&lt;br /&gt;
typedef struct {&lt;br /&gt;
	INT32 type;				/* string type */&lt;br /&gt;
	INT32 scope;				/* string variable scope */&lt;br /&gt;
	INT32 temp;				/* memory release flag */&lt;br /&gt;
	INT32 alloc_size;			/* number of bytes allocated */&lt;br /&gt;
	INT32 occup_size;			/* number of bytes occupied */&lt;br /&gt;
	INT32 num_chars;			/* number of characters */&lt;br /&gt;
	UINT32 counter;				/* assignment counter */&lt;br /&gt;
	SEMM_ID mutex;				/* mutex */&lt;br /&gt;
	unsigned char* data;			/* pointer to string */&lt;br /&gt;
	FUNCPTR FuncUpdateString;		/* pointer to callback function */&lt;br /&gt;
	INT32 FuncUpdateStringParam;		/* parameter of callback function */&lt;br /&gt;
} SYS_STRING;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the declaration of the C function that receives the string, specify the string argument:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int MY_C_FUNCTION(int some_var, SYS_STRING* some_str)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In the import_c command that declares the interface from MC-Basic to C function, declare:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
import_c MY_C_FUNCTION(byval as long, byval as string) as long&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using Linux sys.log from Shared Object context==&lt;br /&gt;
It is possible to log messages in the Linux logger sys.log. In order to do so you need to include in your code the following declarations:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/**************************    Linux sys.log Declarations    ******************************/&lt;br /&gt;
&lt;br /&gt;
/* MC Modules */&lt;br /&gt;
#define MODULE_NON	 	 0&lt;br /&gt;
#define MODULE_MOTION		 1&lt;br /&gt;
#define MODULE_RTS		 2&lt;br /&gt;
#define MODULE_TRANSLAT		 3&lt;br /&gt;
#define MODULE_SERCOS		 4&lt;br /&gt;
#define MODULE_ROBOT		 5&lt;br /&gt;
#define MODULE_TRACER		 6&lt;br /&gt;
#define MODULE_SYSTEM		 7&lt;br /&gt;
#define MODULE_MEMORY		 8&lt;br /&gt;
#define MODULE_FILE_SYSTEM	 9&lt;br /&gt;
#define MODULE_CLI		10&lt;br /&gt;
#define MODULE_RBOOTP		11&lt;br /&gt;
#define MODULE_ETHERCAT		12&lt;br /&gt;
#define MODULE_FASTDATA		13&lt;br /&gt;
#define MODULE_UAC		14&lt;br /&gt;
#define MODULE_MC_BASIC		15&lt;br /&gt;
#define MODULE_CANOPEN		16&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* MC Log Level */&lt;br /&gt;
#define LOG_LEVEL_NON		0&lt;br /&gt;
#define LOG_LEVEL_ERROR		1&lt;br /&gt;
#define LOG_LEVEL_WARNING	2&lt;br /&gt;
#define LOG_LEVEL_NOTE		3&lt;br /&gt;
#define LOG_LEVEL_DEBUG		4&lt;br /&gt;
#define LOG_LEVEL_ALL		5&lt;br /&gt;
&lt;br /&gt;
extern int sys_log(int sub_system, int _debug_level, const char * fmt, int arg1, int arg2,&lt;br /&gt;
			int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10);&lt;br /&gt;
&lt;br /&gt;
/******************************************************************************************/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To send a message to sys.log invoke sys_log with fmt as a printf formatted string.&lt;br /&gt;
A more thorough explanation about sys.log and an example can be found in [[Program_Examples:sys_log|Linux sys.log]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
Extract Shared_Object.ZIP to find the above examples&amp;lt;br/&amp;gt;&lt;br /&gt;
[[File:Shared_Object.zip||Shared_Object.zip]]&lt;br /&gt;
&lt;br /&gt;
The example corresponds to commit SHA-1: 5228016ac44122213dcb05d781b15c8e05054d5b in GIT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
* [[MC-Basic_C-Interface|MC-Basic C-Interface]]&lt;br /&gt;
* [[MC-Basic:IMPORT_C|IMPORT_C]]&lt;br /&gt;
* [[Program_Examples:sys_log|Linux sys.log]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Program_Examples:TCP_IP:TCPIP_TelNet_Server&amp;diff=125653</id>
		<title>Program Examples:TCP IP:TCPIP TelNet Server</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Program_Examples:TCP_IP:TCPIP_TelNet_Server&amp;diff=125653"/>
				<updated>2015-11-03T15:36:18Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The following example demonstrates the set up of a TelNet TCP-IP server.&lt;br /&gt;
&lt;br /&gt;
The server opens a socket and blocks on &amp;quot;Accept&amp;quot; until a telnet session gets connected. A 'How To Use' guide is sent to the telnet explaining the basic functionality on the client side.&lt;br /&gt;
&lt;br /&gt;
Once the program is running, open a telnet console by clicking the windows icon start--&amp;gt;run and enter:&lt;br /&gt;
&lt;br /&gt;
telnet mc.ip.add.ress 6001&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
common shared Running_TCP_Server as long = 1&lt;br /&gt;
common shared x as long = 0&lt;br /&gt;
common shared y as long = 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
program 'continue&lt;br /&gt;
&lt;br /&gt;
	dim main_str as string&lt;br /&gt;
	dim chr_str as string&lt;br /&gt;
	dim i as long = 0&lt;br /&gt;
	dim tokens[64] as string&lt;br /&gt;
	dim num_of_tokens as long&lt;br /&gt;
&lt;br /&gt;
	Try&lt;br /&gt;
		OpenSocket Options=1 as #1&lt;br /&gt;
	catch 5043 'socket is already open&lt;br /&gt;
		print &amp;quot;socket 1 is already open. Closing and reopening&amp;quot;&lt;br /&gt;
		close #1&lt;br /&gt;
		OpenSocket Options=1 as #1&lt;br /&gt;
	End Try&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	main_str = &amp;quot;Welcome to TelNet TCP/IP Server&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	Accept(#1, 6001)&lt;br /&gt;
	print #1,main_str&lt;br /&gt;
	print #1,&amp;quot;recognizes 2 variables x and y&amp;quot;&lt;br /&gt;
	print #1,&amp;quot;Set variable&amp;quot;&lt;br /&gt;
	print #1,&amp;quot;x value &amp;lt;enter&amp;gt;&amp;quot;&lt;br /&gt;
	print #1,&amp;quot;y value &amp;lt;enter&amp;gt;&amp;quot;&lt;br /&gt;
	print #1,&amp;quot;read variable&amp;quot;&lt;br /&gt;
	print #1,&amp;quot;x &amp;lt;enter&amp;gt;&amp;quot;&lt;br /&gt;
	print #1,&amp;quot;y &amp;lt;enter&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	main_str = &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	while Running_TCP_Server&lt;br /&gt;
&lt;br /&gt;
		if loc(1) = 0 then  '  if no characters are waiting to be read&lt;br /&gt;
			sleep 10&lt;br /&gt;
			else&lt;br /&gt;
&lt;br /&gt;
			chr_str = input$(1,#1)   '  receive one byte&lt;br /&gt;
			print chr_str  '  DEBUG&lt;br /&gt;
			main_str = main_str + chr_str&lt;br /&gt;
			if asc(chr_str) = 0xA then  '  Line Feed - The client clicked return&lt;br /&gt;
				print main_str  '  DEBUG&lt;br /&gt;
&lt;br /&gt;
				num_of_tokens = TokenizeStr(main_str,tokens)&lt;br /&gt;
				call ParseStr(main_str,tokens,num_of_tokens)&lt;br /&gt;
				main_str = &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
			end if&lt;br /&gt;
&lt;br /&gt;
			sleep 10&lt;br /&gt;
&lt;br /&gt;
		end if&lt;br /&gt;
&lt;br /&gt;
	end while&lt;br /&gt;
&lt;br /&gt;
	main_str = &amp;quot;Closing TelNet TCP/IP Server&amp;quot;&lt;br /&gt;
	print #1,main_str; 'send&lt;br /&gt;
&lt;br /&gt;
	close #1&lt;br /&gt;
	Print &amp;quot;Server Closed Sockets. Server Exits&amp;quot;&lt;br /&gt;
&lt;br /&gt;
end program&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sub ParseStr(str_to_parse as string, tokens[*] as string,byval num_of_tokens as long)&lt;br /&gt;
&lt;br /&gt;
	select case tokens[1]&lt;br /&gt;
&lt;br /&gt;
		case &amp;quot;x&amp;quot;&lt;br /&gt;
			if (1 = num_of_tokens ) then&lt;br /&gt;
				print #1, x&lt;br /&gt;
			else&lt;br /&gt;
				x = val(tokens[2])&lt;br /&gt;
			end if&lt;br /&gt;
&lt;br /&gt;
		case &amp;quot;y&amp;quot;&lt;br /&gt;
			if (1 = num_of_tokens ) then&lt;br /&gt;
				print #1, y&lt;br /&gt;
			else&lt;br /&gt;
				y = val(tokens[2])&lt;br /&gt;
			end if&lt;br /&gt;
&lt;br /&gt;
		case &amp;quot;quit&amp;quot;&lt;br /&gt;
			Running_TCP_Server = 0&lt;br /&gt;
&lt;br /&gt;
		case else&lt;br /&gt;
			print #1, &amp;quot;Error&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	end select&lt;br /&gt;
&lt;br /&gt;
end sub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function TokenizeStr(byval str_to_tokenize as string, tokens[*] as string) as long&lt;br /&gt;
&lt;br /&gt;
	dim space_index as long = 1&lt;br /&gt;
&lt;br /&gt;
	TokenizeStr = 1&lt;br /&gt;
&lt;br /&gt;
	while space_index &amp;lt;&amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
		space_index = instr(str_to_tokenize, &amp;quot; &amp;quot;)&lt;br /&gt;
		if space_index &amp;lt;&amp;gt; 0 then&lt;br /&gt;
			tokens[TokenizeStr] = left$(str_to_tokenize, space_index - 1)&lt;br /&gt;
			str_to_tokenize = right$(str_to_tokenize, len(str_to_tokenize) - space_index)&lt;br /&gt;
			TokenizeStr = TokenizeStr + 1&lt;br /&gt;
		end if&lt;br /&gt;
&lt;br /&gt;
	end while&lt;br /&gt;
&lt;br /&gt;
	tokens[TokenizeStr] = left$(str_to_tokenize, len(str_to_tokenize) - 2)&lt;br /&gt;
&lt;br /&gt;
end function&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The example corresponds to commit SHA-1: 0013794b23d0976ecda4ac880eac706c4d3e34bb in GIT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
* [[Program Examples:TCP IP:TCPIP Simple Server|TCP/IP Simple Server]]&lt;br /&gt;
* [[Program Examples:TCP IP:TCPIP Simple Client|TCP/IP Simple Client]]&lt;br /&gt;
* [[Program Examples:TCP IP:TCPIP Multi Server|TCP/IP Multi Clients Server]]&lt;br /&gt;
* [[Program_Examples:TCP_IP:TCPIP_Winsock_Client|TCP/IP windows socket client]]&lt;br /&gt;
* [[MC-Basic:ACCEPT|ACCEPT]]&lt;br /&gt;
* [[MC-Basic:CLOSE|CLOSE]]&lt;br /&gt;
* [[MC-Basic:CONNECT|CONNECT]]&lt;br /&gt;
* [[MC-Basic:OPENSOCKET|OPENSOCKET]]&lt;br /&gt;
* [[MC-Basic:INPUT$|INPUT$]]&lt;br /&gt;
* [[MC-Basic:PING|PING]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Program_Examples:TCP_IP:TCPIP_TelNet_Server&amp;diff=125652</id>
		<title>Program Examples:TCP IP:TCPIP TelNet Server</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Program_Examples:TCP_IP:TCPIP_TelNet_Server&amp;diff=125652"/>
				<updated>2015-11-03T15:35:44Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The following example demonstrates the set up of a TelNet TCP-IP server.&lt;br /&gt;
&lt;br /&gt;
The server opens a socket and blocks on &amp;quot;Accept&amp;quot; until a telnet session gets connected. A 'How To Use' guide is sent to the telnet explaining the basic functionality on the client side.&lt;br /&gt;
&lt;br /&gt;
Once the program is running, open a telnet console by clicking the windows icon start-&amp;gt;run and enter:&lt;br /&gt;
&lt;br /&gt;
telnet mc.ip.add.ress 6001&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
common shared Running_TCP_Server as long = 1&lt;br /&gt;
common shared x as long = 0&lt;br /&gt;
common shared y as long = 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
program 'continue&lt;br /&gt;
&lt;br /&gt;
	dim main_str as string&lt;br /&gt;
	dim chr_str as string&lt;br /&gt;
	dim i as long = 0&lt;br /&gt;
	dim tokens[64] as string&lt;br /&gt;
	dim num_of_tokens as long&lt;br /&gt;
&lt;br /&gt;
	Try&lt;br /&gt;
		OpenSocket Options=1 as #1&lt;br /&gt;
	catch 5043 'socket is already open&lt;br /&gt;
		print &amp;quot;socket 1 is already open. Closing and reopening&amp;quot;&lt;br /&gt;
		close #1&lt;br /&gt;
		OpenSocket Options=1 as #1&lt;br /&gt;
	End Try&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	main_str = &amp;quot;Welcome to TelNet TCP/IP Server&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	Accept(#1, 6001)&lt;br /&gt;
	print #1,main_str&lt;br /&gt;
	print #1,&amp;quot;recognizes 2 variables x and y&amp;quot;&lt;br /&gt;
	print #1,&amp;quot;Set variable&amp;quot;&lt;br /&gt;
	print #1,&amp;quot;x value &amp;lt;enter&amp;gt;&amp;quot;&lt;br /&gt;
	print #1,&amp;quot;y value &amp;lt;enter&amp;gt;&amp;quot;&lt;br /&gt;
	print #1,&amp;quot;read variable&amp;quot;&lt;br /&gt;
	print #1,&amp;quot;x &amp;lt;enter&amp;gt;&amp;quot;&lt;br /&gt;
	print #1,&amp;quot;y &amp;lt;enter&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	main_str = &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	while Running_TCP_Server&lt;br /&gt;
&lt;br /&gt;
		if loc(1) = 0 then  '  if no characters are waiting to be read&lt;br /&gt;
			sleep 10&lt;br /&gt;
			else&lt;br /&gt;
&lt;br /&gt;
			chr_str = input$(1,#1)   '  receive one byte&lt;br /&gt;
			print chr_str  '  DEBUG&lt;br /&gt;
			main_str = main_str + chr_str&lt;br /&gt;
			if asc(chr_str) = 0xA then  '  Line Feed - The client clicked return&lt;br /&gt;
				print main_str  '  DEBUG&lt;br /&gt;
&lt;br /&gt;
				num_of_tokens = TokenizeStr(main_str,tokens)&lt;br /&gt;
				call ParseStr(main_str,tokens,num_of_tokens)&lt;br /&gt;
				main_str = &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
			end if&lt;br /&gt;
&lt;br /&gt;
			sleep 10&lt;br /&gt;
&lt;br /&gt;
		end if&lt;br /&gt;
&lt;br /&gt;
	end while&lt;br /&gt;
&lt;br /&gt;
	main_str = &amp;quot;Closing TelNet TCP/IP Server&amp;quot;&lt;br /&gt;
	print #1,main_str; 'send&lt;br /&gt;
&lt;br /&gt;
	close #1&lt;br /&gt;
	Print &amp;quot;Server Closed Sockets. Server Exits&amp;quot;&lt;br /&gt;
&lt;br /&gt;
end program&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sub ParseStr(str_to_parse as string, tokens[*] as string,byval num_of_tokens as long)&lt;br /&gt;
&lt;br /&gt;
	select case tokens[1]&lt;br /&gt;
&lt;br /&gt;
		case &amp;quot;x&amp;quot;&lt;br /&gt;
			if (1 = num_of_tokens ) then&lt;br /&gt;
				print #1, x&lt;br /&gt;
			else&lt;br /&gt;
				x = val(tokens[2])&lt;br /&gt;
			end if&lt;br /&gt;
&lt;br /&gt;
		case &amp;quot;y&amp;quot;&lt;br /&gt;
			if (1 = num_of_tokens ) then&lt;br /&gt;
				print #1, y&lt;br /&gt;
			else&lt;br /&gt;
				y = val(tokens[2])&lt;br /&gt;
			end if&lt;br /&gt;
&lt;br /&gt;
		case &amp;quot;quit&amp;quot;&lt;br /&gt;
			Running_TCP_Server = 0&lt;br /&gt;
&lt;br /&gt;
		case else&lt;br /&gt;
			print #1, &amp;quot;Error&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	end select&lt;br /&gt;
&lt;br /&gt;
end sub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function TokenizeStr(byval str_to_tokenize as string, tokens[*] as string) as long&lt;br /&gt;
&lt;br /&gt;
	dim space_index as long = 1&lt;br /&gt;
&lt;br /&gt;
	TokenizeStr = 1&lt;br /&gt;
&lt;br /&gt;
	while space_index &amp;lt;&amp;gt; 0&lt;br /&gt;
&lt;br /&gt;
		space_index = instr(str_to_tokenize, &amp;quot; &amp;quot;)&lt;br /&gt;
		if space_index &amp;lt;&amp;gt; 0 then&lt;br /&gt;
			tokens[TokenizeStr] = left$(str_to_tokenize, space_index - 1)&lt;br /&gt;
			str_to_tokenize = right$(str_to_tokenize, len(str_to_tokenize) - space_index)&lt;br /&gt;
			TokenizeStr = TokenizeStr + 1&lt;br /&gt;
		end if&lt;br /&gt;
&lt;br /&gt;
	end while&lt;br /&gt;
&lt;br /&gt;
	tokens[TokenizeStr] = left$(str_to_tokenize, len(str_to_tokenize) - 2)&lt;br /&gt;
&lt;br /&gt;
end function&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The example corresponds to commit SHA-1: 0013794b23d0976ecda4ac880eac706c4d3e34bb in GIT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
* [[Program Examples:TCP IP:TCPIP Simple Server|TCP/IP Simple Server]]&lt;br /&gt;
* [[Program Examples:TCP IP:TCPIP Simple Client|TCP/IP Simple Client]]&lt;br /&gt;
* [[Program Examples:TCP IP:TCPIP Multi Server|TCP/IP Multi Clients Server]]&lt;br /&gt;
* [[Program_Examples:TCP_IP:TCPIP_Winsock_Client|TCP/IP windows socket client]]&lt;br /&gt;
* [[MC-Basic:ACCEPT|ACCEPT]]&lt;br /&gt;
* [[MC-Basic:CLOSE|CLOSE]]&lt;br /&gt;
* [[MC-Basic:CONNECT|CONNECT]]&lt;br /&gt;
* [[MC-Basic:OPENSOCKET|OPENSOCKET]]&lt;br /&gt;
* [[MC-Basic:INPUT$|INPUT$]]&lt;br /&gt;
* [[MC-Basic:PING|PING]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Program_Examples:Create_Motion:CAM_Table&amp;diff=125568</id>
		<title>Program Examples:Create Motion:CAM Table</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Program_Examples:Create_Motion:CAM_Table&amp;diff=125568"/>
				<updated>2015-09-07T13:16:38Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The following example demonstrates how to create and use a CAM table.&amp;lt;br/&amp;gt;&lt;br /&gt;
Refer to [[Axis_Setup_Procedure|Axis Setup Procedure]] for an explanation and an example of how to set up an axis.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'**********************************************************************************************************&lt;br /&gt;
' File:			CAM_MOVE.PRG&lt;br /&gt;
' Purpose:		Move two axes with CAM table and master-slave&lt;br /&gt;
' Version:		1.00&lt;br /&gt;
' Author:		Nir Geller&lt;br /&gt;
' Description:	This is an example of use of a CAM table. Initialize a CAM table with a sinus function character,&lt;br /&gt;
'				and set master - slave relations between two axes. Move the master axis and see how the slave axis&lt;br /&gt;
'				follows according to the cam table.&lt;br /&gt;
'&lt;br /&gt;
'				Record or watch the PFB of AX_MASTER and AX_SLAVE.&lt;br /&gt;
'&lt;br /&gt;
'**********************************************************************************************************&lt;br /&gt;
&lt;br /&gt;
'Declaring a cam-table type global variable:&lt;br /&gt;
common shared CamTable1 as cam&lt;br /&gt;
&lt;br /&gt;
program&lt;br /&gt;
&lt;br /&gt;
	call SetCAM&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
	attach AX_MASTER&lt;br /&gt;
	attach AX_SLAVE&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
	'call EC_SET_MOTION_OPMODE(AX_MASTER, POSITIONMODE)&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
	AX_MASTER.en = 1&lt;br /&gt;
	AX_SLAVE.en = 1&lt;br /&gt;
 &lt;br /&gt;
	sleep 1000&lt;br /&gt;
 &lt;br /&gt;
	while 1&lt;br /&gt;
 &lt;br /&gt;
		MOVE AX_MASTER 1000 vcruise=1000 starttype=immediate abs = 1&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
		while AX_MASTER.IsMoving &amp;lt;&amp;gt; 0&lt;br /&gt;
			sleep 1000&lt;br /&gt;
		end while&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
		MOVE AX_MASTER 0 vcruise=1000 starttype=immediate abs = 1&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
		while AX_MASTER.IsMoving &amp;lt;&amp;gt; 0&lt;br /&gt;
			sleep 1000&lt;br /&gt;
		end while&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
	end while&lt;br /&gt;
 &lt;br /&gt;
	detach AX_MASTER&lt;br /&gt;
	detach AX_SLAVE&lt;br /&gt;
&lt;br /&gt;
end program&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'****************************************************************************&lt;br /&gt;
' Subroutine Name: SetCAM&lt;br /&gt;
' Description: Initialize a CAM table with a sinus function character, and set&lt;br /&gt;
'				master - slave relations between two axes.&lt;br /&gt;
' Called From: Program&lt;br /&gt;
' Author: Nir Geller&lt;br /&gt;
' Input Parameters: None&lt;br /&gt;
' Output Parameters: None&lt;br /&gt;
' Return Value: None&lt;br /&gt;
' Algorithm:&lt;br /&gt;
' Global Variables Used:&lt;br /&gt;
' Revisions:&lt;br /&gt;
'****************************************************************************&lt;br /&gt;
sub SetCAM&lt;br /&gt;
&lt;br /&gt;
	dim camsize as long = 10000&lt;br /&gt;
	dim cam_amplitude as long = 100&lt;br /&gt;
	dim i as long = 0&lt;br /&gt;
&lt;br /&gt;
	'Creating an empty cam table:&lt;br /&gt;
	'This table is cyclic:&lt;br /&gt;
	CamTable1.Cycle = -1&lt;br /&gt;
&lt;br /&gt;
	'Not linked to any other cam-tables:&lt;br /&gt;
	CamTable1.Next = none&lt;br /&gt;
	CamTable1.Prev = none&lt;br /&gt;
&lt;br /&gt;
	'Making it 10000 points&lt;br /&gt;
	createcamdata camsize CamTable1&lt;br /&gt;
&lt;br /&gt;
	'Defining a 360 deg sine table:&lt;br /&gt;
	for i = 1 to CamTable1.Size &lt;br /&gt;
		CamTable1.MasterData [i] = 360*(i-1)/CamTable1.Size ' Master in degrees&lt;br /&gt;
		CamTable1.SlaveData  [i] = cam_amplitude *sin (CamTable1.MasterData [i] * pi/180)&lt;br /&gt;
	next&lt;br /&gt;
&lt;br /&gt;
	'Store the newly created file onto flash disk:&lt;br /&gt;
	storecamdata ct1.cam CamTable1&lt;br /&gt;
&lt;br /&gt;
	'Once the table is stored on the flash it can be reloaded as:&lt;br /&gt;
	'loadcamdata ct1.cam CamTable1&lt;br /&gt;
&lt;br /&gt;
	print &amp;quot;CAM table set&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	attach AX_MASTER&lt;br /&gt;
	attach AX_SLAVE&lt;br /&gt;
&lt;br /&gt;
		AX_SLAVE.MasterSource = AX_MASTER.PCMD&lt;br /&gt;
		AX_SLAVE.GearRatio = 1.0&lt;br /&gt;
		AX_SLAVE.CamOffset = 0 &lt;br /&gt;
		AX_SLAVE.FirstCam  = CamTable1 &lt;br /&gt;
		AX_SLAVE.slave     = cam&lt;br /&gt;
&lt;br /&gt;
	detach AX_MASTER&lt;br /&gt;
	detach AX_SLAVE&lt;br /&gt;
&lt;br /&gt;
	print &amp;quot;Master-Slave relation set&amp;quot;&lt;br /&gt;
&lt;br /&gt;
end sub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The example corresponds to commit SHA-1: 6b843ca272c3e3d28d36d7116ba9812f4166d97f in GIT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
* [[Axis_Setup_Procedure|Axis Setup Procedure]]&lt;br /&gt;
* [[OperationalModes|Operational Modes]]&lt;br /&gt;
* [[MC-Basic:axis.OPMODE|Axis.OpMode property]]&lt;br /&gt;
* [[MC-Basic:MOVE|MOVE Command]]&lt;br /&gt;
* [[EtherCAT:EC_SET_MOTION_OPMODE|EC_SET_MOTION_OPMODE]]&lt;br /&gt;
* [[Program Examples:Create Motion:Velocity Mode|Velocity Mode - motion example]]&lt;br /&gt;
* [[Program Examples:Create Motion:Torque Mode|Torque Mode - motion example]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Program_Examples:Create_Motion:CAM_Table&amp;diff=125567</id>
		<title>Program Examples:Create Motion:CAM Table</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Program_Examples:Create_Motion:CAM_Table&amp;diff=125567"/>
				<updated>2015-09-07T13:16:19Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The following example demonstrates how to create and use a CAM table.&amp;lt;br/&amp;gt;&lt;br /&gt;
Refer to [[Axis_Setup_Procedure|Axis Setup Procedure]] for an explanation and an example of how to set up an axis.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'**********************************************************************************************************&lt;br /&gt;
' File:			CAM_MOVE.PRG&lt;br /&gt;
' Purpose:		Move two axes with CAM table and master-slave&lt;br /&gt;
' Version:		1.00&lt;br /&gt;
' Author:		Nir Geller&lt;br /&gt;
' Description:	This is an example of use of a CAM table. Initialize a CAM table with a sinus function character,&lt;br /&gt;
'				and set master - slave relations between two axes. Move the master axis and see how the slave axis&lt;br /&gt;
'				follows according to the cam table.&lt;br /&gt;
'&lt;br /&gt;
'				Record or watch the PFB of AX_MASTER and AX_SLAVE.&lt;br /&gt;
'&lt;br /&gt;
'**********************************************************************************************************&lt;br /&gt;
&lt;br /&gt;
'Declaring a cam-table type global variable:&lt;br /&gt;
common shared CamTable1 as cam&lt;br /&gt;
&lt;br /&gt;
program&lt;br /&gt;
&lt;br /&gt;
	call SetCAM&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
	attach AX_MASTER&lt;br /&gt;
	attach AX_SLAVE&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
	'call EC_SET_MOTION_OPMODE(AX_MASTER, POSITIONMODE)&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
	AX_MASTER.en=1&lt;br /&gt;
	AX_SLAVE.en=1&lt;br /&gt;
 &lt;br /&gt;
	sleep 1000&lt;br /&gt;
 &lt;br /&gt;
	while 1&lt;br /&gt;
 &lt;br /&gt;
		MOVE AX_MASTER 1000 vcruise=1000 starttype=immediate abs = 1&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
		while AX_MASTER.IsMoving &amp;lt;&amp;gt; 0&lt;br /&gt;
			sleep 1000&lt;br /&gt;
		end while&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
		MOVE AX_MASTER 0 vcruise=1000 starttype=immediate abs = 1&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
		while AX_MASTER.IsMoving &amp;lt;&amp;gt; 0&lt;br /&gt;
			sleep 1000&lt;br /&gt;
		end while&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
	end while&lt;br /&gt;
 &lt;br /&gt;
	detach AX_MASTER&lt;br /&gt;
	detach AX_SLAVE&lt;br /&gt;
&lt;br /&gt;
end program&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'****************************************************************************&lt;br /&gt;
' Subroutine Name: SetCAM&lt;br /&gt;
' Description: Initialize a CAM table with a sinus function character, and set&lt;br /&gt;
'				master - slave relations between two axes.&lt;br /&gt;
' Called From: Program&lt;br /&gt;
' Author: Nir Geller&lt;br /&gt;
' Input Parameters: None&lt;br /&gt;
' Output Parameters: None&lt;br /&gt;
' Return Value: None&lt;br /&gt;
' Algorithm:&lt;br /&gt;
' Global Variables Used:&lt;br /&gt;
' Revisions:&lt;br /&gt;
'****************************************************************************&lt;br /&gt;
sub SetCAM&lt;br /&gt;
&lt;br /&gt;
	dim camsize as long = 10000&lt;br /&gt;
	dim cam_amplitude as long = 100&lt;br /&gt;
	dim i as long = 0&lt;br /&gt;
&lt;br /&gt;
	'Creating an empty cam table:&lt;br /&gt;
	'This table is cyclic:&lt;br /&gt;
	CamTable1.Cycle = -1&lt;br /&gt;
&lt;br /&gt;
	'Not linked to any other cam-tables:&lt;br /&gt;
	CamTable1.Next = none&lt;br /&gt;
	CamTable1.Prev = none&lt;br /&gt;
&lt;br /&gt;
	'Making it 10000 points&lt;br /&gt;
	createcamdata camsize CamTable1&lt;br /&gt;
&lt;br /&gt;
	'Defining a 360 deg sine table:&lt;br /&gt;
	for i = 1 to CamTable1.Size &lt;br /&gt;
		CamTable1.MasterData [i] = 360*(i-1)/CamTable1.Size ' Master in degrees&lt;br /&gt;
		CamTable1.SlaveData  [i] = cam_amplitude *sin (CamTable1.MasterData [i] * pi/180)&lt;br /&gt;
	next&lt;br /&gt;
&lt;br /&gt;
	'Store the newly created file onto flash disk:&lt;br /&gt;
	storecamdata ct1.cam CamTable1&lt;br /&gt;
&lt;br /&gt;
	'Once the table is stored on the flash it can be reloaded as:&lt;br /&gt;
	'loadcamdata ct1.cam CamTable1&lt;br /&gt;
&lt;br /&gt;
	print &amp;quot;CAM table set&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	attach AX_MASTER&lt;br /&gt;
	attach AX_SLAVE&lt;br /&gt;
&lt;br /&gt;
		AX_SLAVE.MasterSource = AX_MASTER.PCMD&lt;br /&gt;
		AX_SLAVE.GearRatio = 1.0&lt;br /&gt;
		AX_SLAVE.CamOffset = 0 &lt;br /&gt;
		AX_SLAVE.FirstCam  = CamTable1 &lt;br /&gt;
		AX_SLAVE.slave     = cam&lt;br /&gt;
&lt;br /&gt;
	detach AX_MASTER&lt;br /&gt;
	detach AX_SLAVE&lt;br /&gt;
&lt;br /&gt;
	print &amp;quot;Master-Slave relation set&amp;quot;&lt;br /&gt;
&lt;br /&gt;
end sub&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The example corresponds to commit SHA-1: 6b843ca272c3e3d28d36d7116ba9812f4166d97f in GIT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
* [[Axis_Setup_Procedure|Axis Setup Procedure]]&lt;br /&gt;
* [[OperationalModes|Operational Modes]]&lt;br /&gt;
* [[MC-Basic:axis.OPMODE|Axis.OpMode property]]&lt;br /&gt;
* [[MC-Basic:MOVE|MOVE Command]]&lt;br /&gt;
* [[EtherCAT:EC_SET_MOTION_OPMODE|EC_SET_MOTION_OPMODE]]&lt;br /&gt;
* [[Program Examples:Create Motion:Velocity Mode|Velocity Mode - motion example]]&lt;br /&gt;
* [[Program Examples:Create Motion:Torque Mode|Torque Mode - motion example]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=MC-Basic_C-Interface&amp;diff=125555</id>
		<title>MC-Basic C-Interface</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=MC-Basic_C-Interface&amp;diff=125555"/>
				<updated>2015-08-04T09:58:44Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
The softMC offers users an option to incorporate applications written in C or C++ into an MC-Basic task. You can write your algorithm in C/C++, compile it with a GNU compiler, download it into a target program and call the code from a program written in MC-Basic or directly from the command line.&lt;br /&gt;
&lt;br /&gt;
The parameters can be passed by value as well as by reference. This function returns a value that can be processed by an MC-Basic application.&lt;br /&gt;
&lt;br /&gt;
MC-Basic provides a facility to load a user object-file into the RAM of the softMC. This file is relocatable and must include information about global symbols for the softMC to find the C-function. The object module may consist of any number of functions. The only restriction is RAM limit.&lt;br /&gt;
&lt;br /&gt;
= Object Files =&lt;br /&gt;
Object files (extension “.o”), contain compiled C-programs and are stored in the Flash disk. You can '''SEND '''object files to the controller, load files into RAM with '''OLOAD''' and unload them with '''OUNLOAD'''. If '''OLOAD/OUNLOAD''' fails for any reason, details are found in the OLOAD.ERR file.&lt;br /&gt;
&lt;br /&gt;
= Prototypes =&lt;br /&gt;
For the MC-Basic language translator to match function parameters, provide a C-function prototype file (PROTO.PRO). There is also an option to wrire prototypes in library files, within the declarations section, instead of using the PROTO.PRO file. It is important to understand that matching between the provided softMC prototype and actual C implementation cannot be tested by the translator. '''''It is your responsibility to keep consistency between the function prototype and C implementation.'''''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Note|'''''To speedup translation of the prototype file, PROTO.PRO is copied into RAM at startup and at every '''OLOAD'''. When PROTO.PRO is modified and sent to the controller, issue an '''OLOAD''' or reboot the softMC to refresh the prototypes in the RAM.'''''}}&lt;br /&gt;
&lt;br /&gt;
The translator is case-insensitive, while object module loader is case-sensitive, so '''''write the name of a C function in capital letters within the C code'''''. softMC prototypes of C functions and C function calls through the softMC are not case sensitive.&lt;br /&gt;
&lt;br /&gt;
Parameters can be passed “by value” and “by reference”&lt;br /&gt;
&lt;br /&gt;
Few object files may be incrementally linked together.&lt;br /&gt;
&lt;br /&gt;
The general syntax for the softMC prototype of a C-function is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;IMPORT_C &amp;lt;&amp;lt;/nowiki&amp;gt;''Function_Name''&amp;lt;nowiki&amp;gt;&amp;gt; ({AS &amp;lt;&amp;lt;/nowiki&amp;gt;''type''&amp;lt;nowiki&amp;gt;&amp;gt;}, {BYVAL AS {&amp;lt;&amp;lt;/nowiki&amp;gt;''type''&amp;lt;nowiki&amp;gt;&amp;gt;}) {AS &amp;lt;&amp;lt;/nowiki&amp;gt;''type''&amp;gt;}&lt;br /&gt;
&lt;br /&gt;
A parameter passed by value has the BYVAL prefix.&lt;br /&gt;
&lt;br /&gt;
A parameter passed by reference has no prefix.&lt;br /&gt;
&lt;br /&gt;
Prototypes do not include parameter names.&lt;br /&gt;
&lt;br /&gt;
A C function prototype with no parameters is written with empty parentheses:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;IMPORT_C &amp;lt;&amp;lt;/nowiki&amp;gt;''Function_Name''&amp;lt;nowiki&amp;gt;&amp;gt; ( ) {AS &amp;lt;&amp;lt;/nowiki&amp;gt;''type''&amp;gt;}&lt;br /&gt;
&lt;br /&gt;
A C function prototype with no returned value (a void function) is written as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;IMPORT_C &amp;lt;&amp;lt;/nowiki&amp;gt;''Function_Name''&amp;lt;nowiki&amp;gt;&amp;gt; ({AS &amp;lt;&amp;lt;/nowiki&amp;gt;''type''&amp;lt;nowiki&amp;gt;&amp;gt;}, {BYVAL AS {&amp;lt;&amp;lt;/nowiki&amp;gt;''type''&amp;gt;})&lt;br /&gt;
&lt;br /&gt;
A C-function accepts any combination of double-, long- , string-, joint- and location-type parameters. The parameters may be passed “by value” or “by reference”. &lt;br /&gt;
&lt;br /&gt;
The returned value may be long, double, string, joint, location or none (for C functions with void returned value).&lt;br /&gt;
&lt;br /&gt;
Examples of prototypes and implementation:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;border-spacing:0;&amp;quot;&lt;br /&gt;
| style=&amp;quot;border-top:0.039cm double #000000;border-bottom:0.039cm double #000000;border-left:0.039cm double #000000;border-right:none;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| &amp;lt;center&amp;gt;'''MC-Basic Prototype'''&amp;lt;/center&amp;gt;&lt;br /&gt;
| style=&amp;quot;border-top:0.039cm double #000000;border-bottom:0.039cm double #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| &amp;lt;center&amp;gt;'''C Implementation'''&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:0.039cm double #000000;border-bottom:0.018cm solid #000000;border-left:0.039cm double #000000;border-right:none;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| import_c cFunc_LV As Long&lt;br /&gt;
| style=&amp;quot;border-top:0.039cm double #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| int CFUNC_LV(void);&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.039cm double #000000;border-right:none;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| import_c cFunc_DV As Double&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| double CFUNC_DV(void);&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.039cm double #000000;border-right:none;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| import_c cFunc_SV As String&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| SYS_STRING* CFUNC_SV(void);&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.039cm double #000000;border-right:none;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| import_c cFunc_PV As Joint Of XYZR&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| SYS_POINT* CFUNC_PV(void);&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.039cm double #000000;border-right:none;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| import_c cFunc_GPV As Generic Location&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| SYS_POINT* CFUNC_GPV(void);&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.039cm double #000000;border-right:none;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| import_c cFunc_VV()&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| void CFUNC_VV(void);&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.039cm double #000000;border-right:none;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| import_c cFunc_LL(ByVal As Long) As Long&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| int CFUNC_LL(int L);&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.039cm double #000000;border-right:none;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| import_c cFunc_DRD(As Double) As Double&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| double CFUNC_DRD(double* D);&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.039cm double #000000;border-right:none;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| import_c cFunc_SRS(As String) As String&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| SYS_STRING* CFUNC_SRS(SYS_STRING** S);&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.039cm double #000000;border-right:none;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| import_c cFunc_PRP(As Joint Of XY) As Location Of XYZ&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| SYS_POINT* CFUNC_PRP(SYS_STRING** P);&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.039cm double #000000;border-right:none;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| import_c cFunc_GPRGP(As Generic Location) As Generic Joint&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| SYS_POINT* CFUNC_GPRGP(SYS_STRING** P);&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.039cm double #000000;border-left:0.039cm double #000000;border-right:none;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| import_c cFunc_SS(ByVal As String) As String&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.039cm double #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| SYS_STRING* CFUNC_SS(SYS_STRING* S);&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.039cm double #000000;border-left:0.039cm double #000000;border-right:none;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| import_c cFunc_PGP(ByVal As Generic Joint) As Location Of XYZ &lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.039cm double #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| SYS_POINT* CFUNC_PP(SYS_POINT* P);&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.039cm double #000000;border-left:0.039cm double #000000;border-right:none;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| import_c cFunc_GPP(ByVal As Location Of XY) As Generic Joint&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.039cm double #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| SYS_POINT* CFUNC_GPGP(SYS_POINT* P);&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.039cm double #000000;border-right:none;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| Import_c cFunc_LADAD'''('''&amp;lt;nowiki&amp;gt;[*] as Long, [*] As Double&amp;lt;/nowiki&amp;gt;) As Double&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| Double CFUNC_LADAD(Long* L, Double* D);&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.039cm double #000000;border-right:none;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| Import_c cFunc_SAV'''('''&amp;lt;nowiki&amp;gt;[*] as String&amp;lt;/nowiki&amp;gt;)&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| void CFUNC_SAV(SYS_STRING** SA);&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.039cm double #000000;border-right:none;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| Import_c cFunc_GPAPAS'''('''&amp;lt;nowiki&amp;gt;[*] As Generic Joint, [*] As Location Of XY&amp;lt;/nowiki&amp;gt;) As String&lt;br /&gt;
| style=&amp;quot;border-top:0.018cm solid #000000;border-bottom:0.018cm solid #000000;border-left:0.018cm solid #000000;border-right:0.039cm double #000000;padding-top:0cm;padding-bottom:0cm;padding-left:0.191cm;padding-right:0.191cm;&amp;quot;| SYS_STRING* CFUNC_GPAPAS(SYS_POINT** PA1, SYS_POINT** PA2);&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
Parameters can be of type long, double, string, joint or location; in any order, up to 32 parameters.&lt;br /&gt;
&lt;br /&gt;
Only one-dimensional arrays are allowed as C-functions arguments.&lt;br /&gt;
&lt;br /&gt;
C-functions without parameters or returned values are called using a different syntax than their MC-Basic counterparts.&lt;br /&gt;
&lt;br /&gt;
Example for calling C-functions from MC-Basic:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
No Parameters:&lt;br /&gt;
------------- &lt;br /&gt;
' C code: int CFUNC_LV(void) &lt;br /&gt;
?CFUNC_LV()&lt;br /&gt;
&lt;br /&gt;
No Returned Value:&lt;br /&gt;
-----------------&lt;br /&gt;
' C code: void CFUNC_VV(par1 as int)&lt;br /&gt;
CFUNC_VV(10)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example of PROTO.PRO:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
'No Parametrs&lt;br /&gt;
import_c CFUNC_LV() As Long&lt;br /&gt;
import_c CFUNC_DV() As Double&lt;br /&gt;
import_c CFUNC_SV() As String&lt;br /&gt;
import_c CFUNC_PV() As Location Of XYZ&lt;br /&gt;
import_c CFUNC_GPV() As Generic Joint&lt;br /&gt;
import_c CFUNC_VV()&lt;br /&gt;
'A Single &amp;quot;By Value&amp;quot; Parameter&lt;br /&gt;
import_c CFUNC_LL(ByVal As Long) As Long&lt;br /&gt;
import_c CFUNC_DD(ByVal As Double) As Double&lt;br /&gt;
import_c CFUNC_SS(ByVal As String) As String&lt;br /&gt;
import_c CFUNC_PP(ByVal As Joint of XY) As Location Of XYZ&lt;br /&gt;
import_c CFUNC_GPP(ByVal As Generic Location) As Generic Joint&lt;br /&gt;
'A Single &amp;quot;By Reference&amp;quot; Parameter&lt;br /&gt;
import_c CFUNC_LRL(As Long) As Long&lt;br /&gt;
import_c CFUNC_DRD(As Double) As Double&lt;br /&gt;
import_c CFUNC_SRS(As String) As String&lt;br /&gt;
import_c CFUNC_PRP(As Joint of XY) As Location Of XYZ&lt;br /&gt;
import_c CFUNC_GPRP(As Generic Location) As Generic Joint&lt;br /&gt;
'Multiple &amp;quot;By Value&amp;quot; Parameters&lt;br /&gt;
import_c CFUNC_LVALP(ByVal As double, ByVal As Long, ByVal As String) As Long&lt;br /&gt;
import_c CFUNC_VVALP(ByVal As String, ByVal As double, ByVal AS Long)&lt;br /&gt;
'Multiple &amp;quot;By Reference&amp;quot; Parameters&lt;br /&gt;
import_c CFUNC_DREFP(As String, As Long, As Double) As Double&lt;br /&gt;
import_c CFUNC_VREFP(As Long, As Double, As String)&lt;br /&gt;
' Mixed Parameters&lt;br /&gt;
import_c CFUNC_VMIXP(ByVal As Long,As Double,ByVal As String,As String,As Long,ByVal As double) AS Long&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example of test.c:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/* No Parameters */&lt;br /&gt;
int CFUNC_LV(void)&lt;br /&gt;
{&lt;br /&gt;
return 1;&lt;br /&gt;
}&lt;br /&gt;
double CFUNC_DV(void)&lt;br /&gt;
{&lt;br /&gt;
return 2.2;&lt;br /&gt;
}&lt;br /&gt;
char* CFUNC_SV(void)&lt;br /&gt;
{&lt;br /&gt;
return &amp;quot;SV&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
void CFUNC_VV(void)&lt;br /&gt;
{&lt;br /&gt;
int fd = open(&amp;quot;/tyCo/1&amp;quot;,2,0);&lt;br /&gt;
fdprintf(fd,&amp;quot;VV\r\n&amp;quot;);&lt;br /&gt;
close(fd);&lt;br /&gt;
}&lt;br /&gt;
/* A Single &amp;quot;By Value&amp;quot; Parameter */&lt;br /&gt;
int CFUNC_LL(int L)&lt;br /&gt;
{&lt;br /&gt;
L = L + 1;&lt;br /&gt;
return L;&lt;br /&gt;
}&lt;br /&gt;
double CFUNC_DD(double D)&lt;br /&gt;
{&lt;br /&gt;
D = D + 2.2;&lt;br /&gt;
return D;&lt;br /&gt;
}&lt;br /&gt;
SYS_STRING* CFUNC_SS(SYS_STRING* S)&lt;br /&gt;
{&lt;br /&gt;
strcpy(S,&amp;quot;SS&amp;quot;);&lt;br /&gt;
return S;&lt;br /&gt;
}&lt;br /&gt;
/* A Single &amp;quot;By Reference&amp;quot; Parameter */&lt;br /&gt;
int CFUNC_LRL(int* L)&lt;br /&gt;
{&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*L = *L + 3;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
return *L;&lt;br /&gt;
}&lt;br /&gt;
double CFUNC_DRD(double* D)&lt;br /&gt;
{&lt;br /&gt;
&amp;lt;nowiki&amp;gt;*D = *D + 4.4;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
return *D;&lt;br /&gt;
}&lt;br /&gt;
SYS_STRING* CFUNC_SRS(SYS_STRING** S)&lt;br /&gt;
{&lt;br /&gt;
strcpy(*S,&amp;quot;SRS&amp;quot;);&lt;br /&gt;
return *S;&lt;br /&gt;
}&lt;br /&gt;
/* Multiple Parameters */&lt;br /&gt;
/* By Value Parameters */&lt;br /&gt;
int CFUNC_LVALP(double D, int L, SYS_STRING* S)&lt;br /&gt;
return (D + L + atoi(S)); &lt;br /&gt;
} &lt;br /&gt;
void CFUNC_VVALP(SYS_STRING* S, double D, int L)&lt;br /&gt;
{&lt;br /&gt;
int fd = open(&amp;quot;/tyCo/1&amp;quot;,2,0);&lt;br /&gt;
fdprintf(fd,&amp;quot;Original Values:%d, %f, %s\r\n&amp;quot;, L, D, S);&lt;br /&gt;
L = 10;&lt;br /&gt;
D = 22.2;&lt;br /&gt;
strcpy(S,&amp;quot;VValP&amp;quot;);&lt;br /&gt;
fdprintf(fd,&amp;quot;New Value:%d, %f, %s\r\n&amp;quot;, L, D, S);&lt;br /&gt;
close(fd); &lt;br /&gt;
} &lt;br /&gt;
/* By Reference Parameters */&lt;br /&gt;
double CFUNC_DREFP(SYS_STRING** S, int* L, double* D)&lt;br /&gt;
{&lt;br /&gt;
return (*D + *L + atof(*S)); &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Using MC-Basic Strings in C Functions =&lt;br /&gt;
&lt;br /&gt;
In C functions code,  there must a distinction between local “internal” strings, used only within function block, and “external” strings, originated form MC-basic code  (parameters), or returned to MC-basic code (returned values). While regular ANSI strings can be used as “internal” strings, “external” strings are MC string data structure.&lt;br /&gt;
&lt;br /&gt;
=== The String Library ===&lt;br /&gt;
This library provides functions that enable access to various fields of the string data structutre. Therefore, C function files should include a link to“Strings.pro”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;int str_GetType (SYS_STRING* string)&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
Returns the string’s type: 0 (no type, used for string values and unassigned returned values), 1 (ASCII-8 type) or 2 (UTF-8 type). Returns ERROR (-1) if string parameter is NULL.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;int str_ GetMemSize (SYS_STRING* string)&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
Returns the amount of bytes allocated for the string. Returns ERROR (-1) if string parameter is NULL.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;int str_GetNumBytes (SYS_STRING* string)&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
Returns the actual length of the string in bytes, not including a null-terminator. This size might be smaller than memory size. Returns ERROR (-1) if string parameter is NULL.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;int str_GetNumSymbols (SYS_STRING* string)&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
Returns the number of Unicode symbols within the string, not including the null-terminator.  This value should be identical to str_GetNumBytes() value (see above) in ASCII-8 strings, and might be smaller than str_GetNumBytes() value in UTF-8 strings. Returns ERROR (-1) if string parameter is NULL.&lt;br /&gt;
	&lt;br /&gt;
&amp;lt;b&amp;gt;unsigned char* str_GetData (SYS_STRING* string)&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
Returns the string itself. The string is null-terminated, but may include more null characters in other locations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;int str_Strcpy (SYS_STRING* dest, const char* source, int size)&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
This function replaces the ANSI strcpy function, which copies “size” bytes from “source” string into the “dest” string data structure without using a null-terminator. str_Strcpy()  also updates the string size field, and calculates the new number of symbols according to string type. &lt;br /&gt;
Returns ERROR (-1) if value of size parameter is larger than size of memory allocated for the string, or if one of the pointer parameters is NULL. Returns OK (0) for successful string copy.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;SYS_STRING* str_GetString (unsigned char* data, int data_size, int type)&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
This function creates a new string data structure, with”type” string type. It first allocates a new string data structure, and then allocates “size” bytes through malloc() for the “data” string.  Then, str_Strcpy() (see above) is called to copy “data” string to the new string data structure. &lt;br /&gt;
Returns the address of the new string data structure, or NULL if memory allocation or str_Strcpy() fails.&lt;br /&gt;
&lt;br /&gt;
=== Querying String Parameters ===&lt;br /&gt;
&lt;br /&gt;
In the new string data structures of MC, strings’ data cannot be applied directly as in ANSI strings. Therefore, string’s data should be applied through str_GetData(&amp;lt;string_data_ structure&amp;gt;). All other fields of string data structure should be addressed likewise, using the appropriated str_Get… function from String library (see above).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include “String.pro&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
By Value Parameters:&lt;br /&gt;
-------------------&lt;br /&gt;
&lt;br /&gt;
… CFUNC1(…, SYS_STRING* ValStr, …)&lt;br /&gt;
{&lt;br /&gt;
	char Cstring[100];  /* Local ANSI string */&lt;br /&gt;
	strcpy(Cstring, str_GetData(ValStr));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
By Reference Parameters:&lt;br /&gt;
-----------------------&lt;br /&gt;
&lt;br /&gt;
… CFUNC2(…, SYS_STRING** RefStr, …)&lt;br /&gt;
{&lt;br /&gt;
	printf(“%s\n”, str_GetData(*RefStr));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
By Reference Array Parameters:&lt;br /&gt;
-----------------------------&lt;br /&gt;
&lt;br /&gt;
… CFUNC3(…, SYS_STRING** RefStrArr, …)&lt;br /&gt;
{&lt;br /&gt;
	char CStringArr[10][60];  /* Local ANSI string */&lt;br /&gt;
&lt;br /&gt;
	if (strcmp(str_GetData(RefStrArr[2]),CstringArr[2])      &lt;br /&gt;
	{&lt;br /&gt;
	  …&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Assignment of String Parameters ===&lt;br /&gt;
&lt;br /&gt;
The str_StrCpy() function (see above) was designed for assignmnet of a string parameters.  If str_StrCpy() returns ERROR (-1), an error message should be raised, since the amount of memory allocated for the string is probably not enough for the new string. &lt;br /&gt;
Memory release and realloction of MC string parameters within C code should be avoided, since it might cause memory management problems.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include “String.pro&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
… CFUNC6(…, SYS_STRING** MCString, …) /* MC string */	&lt;br /&gt;
{&lt;br /&gt;
  char CString[20]; /* Local ANSI string */&lt;br /&gt;
&lt;br /&gt;
	&lt;br /&gt;
  if( str_Strcpy(*MCString,Cstring,strlen(Cstring)!=OK) )&lt;br /&gt;
  {&lt;br /&gt;
    printf(&amp;quot;Not enough memory in string parameter\n&amp;quot;)&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Strings as Returned-Values ===&lt;br /&gt;
A returned string cannot be an ANSI string, but must be a string data structure. The returned string data structure must be newly allocated through str_GetString() function (see above).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include “String.pro&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
SYS_STRING* CFUNC4(…)&lt;br /&gt;
{&lt;br /&gt;
 char CString[20]; /* Local ANSI string */&lt;br /&gt;
 int size;&lt;br /&gt;
&lt;br /&gt;
 size = strlen(Cstring);&lt;br /&gt;
&lt;br /&gt;
 return str_GetString(Cstring, size, ASCII8_STRING_TYPE);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Special Considerations =&lt;br /&gt;
Motion and System properties can only be passed by value.&lt;br /&gt;
&lt;br /&gt;
'''KILLTASK''' will not unblock a task locked inside the C-function. An endless block on a semaphore, message queue, etc. inside a C-function prevent sa task from correct being killed. If C-function has some blocking operation system call (e.g., puting a task to sleep, taking a semaphore, passing messages through a message queue, IO operation, etc.), this may interfere with killing the user task.&lt;br /&gt;
&lt;br /&gt;
When an object module is loaded several times without unloading, all its instances are kept in the RAM, while the system symbol table has references only to the resent instance. MC-Basic applications may refer to the obsolete version of some modified object file.&lt;br /&gt;
&lt;br /&gt;
'''OUNLOAD''' does not check to see if the object file is in use. It is your responsibility to ensure that the object is not unloaded as long as there tasks and libraries that refer to the object.&lt;br /&gt;
&lt;br /&gt;
Consider following example, both the program TASK1.PRG and TASK2.PRG use the same function from object module.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--&amp;gt;oload my_obj.o&lt;br /&gt;
--&amp;gt;load TASK1.PRG&lt;br /&gt;
--&amp;gt;send my_obj.o ‘ send updated version of object file&lt;br /&gt;
--&amp;gt;oload my_obj.o&lt;br /&gt;
--&amp;gt;load TASK2.PRG&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example, TASK1.PRG references the oldest instance of my_obj.o while TASK2.PRG references the recent version.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
* [[MC-Basic:IMPORT_C|IMPORT_C]]&lt;br /&gt;
* [[Program_Examples:Shared_Objects|Shared Objects]]&lt;br /&gt;
* [[Program_Examples:sys_log|Linux sys.log]]&lt;br /&gt;
&lt;br /&gt;
[[Category:MC-Basic|C-Interface]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Program_Examples:Shared_Objects&amp;diff=125554</id>
		<title>Program Examples:Shared Objects</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Program_Examples:Shared_Objects&amp;diff=125554"/>
				<updated>2015-08-04T09:57:33Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The following example demonstrates how to compile a shared object in Linux and link it with softMC at run-time.&lt;br /&gt;
&lt;br /&gt;
Below there are 5 example files: A C source file, a C header file, a CPP source file, a CPP header file and a makefile.&amp;lt;br/&amp;gt;&lt;br /&gt;
The source and header files implement a simple program that is given 2 integers as arguments and returns their sum or difference.&amp;lt;br/&amp;gt;&lt;br /&gt;
This program DOESN'T include a main function, therefore the program can be compiled only into a library, and not an executable.&lt;br /&gt;
&lt;br /&gt;
==Example Program==&lt;br /&gt;
C Source file: Example.c&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;Example.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
/**************************    Linux sys.log Declarations    ******************************/&lt;br /&gt;
&lt;br /&gt;
/* MC Modules */&lt;br /&gt;
#define MODULE_NON	 	 0&lt;br /&gt;
#define MODULE_MOTION		 1&lt;br /&gt;
#define MODULE_RTS		 2&lt;br /&gt;
#define MODULE_TRANSLAT		 3&lt;br /&gt;
#define MODULE_SERCOS		 4&lt;br /&gt;
#define MODULE_ROBOT		 5&lt;br /&gt;
#define MODULE_TRACER		 6&lt;br /&gt;
#define MODULE_SYSTEM		 7&lt;br /&gt;
#define MODULE_MEMORY		 8&lt;br /&gt;
#define MODULE_FILE_SYSTEM	 9&lt;br /&gt;
#define MODULE_CLI		10&lt;br /&gt;
#define MODULE_RBOOTP		11&lt;br /&gt;
#define MODULE_ETHERCAT		12&lt;br /&gt;
#define MODULE_FASTDATA		13&lt;br /&gt;
#define MODULE_UAC		14&lt;br /&gt;
#define MODULE_MC_BASIC		15&lt;br /&gt;
#define MODULE_CANOPEN		16&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* MC Log Level */&lt;br /&gt;
#define LOG_LEVEL_NON		0&lt;br /&gt;
#define LOG_LEVEL_ERROR		1&lt;br /&gt;
#define LOG_LEVEL_WARNING	2&lt;br /&gt;
#define LOG_LEVEL_NOTE		3&lt;br /&gt;
#define LOG_LEVEL_DEBUG		4&lt;br /&gt;
#define LOG_LEVEL_ALL		5&lt;br /&gt;
&lt;br /&gt;
extern int sys_log(int sub_system, int _debug_level, const char * fmt, int arg1, int arg2,&lt;br /&gt;
			int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10);&lt;br /&gt;
&lt;br /&gt;
/******************************************************************************************/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int SHARED_OBJECT_SUM(int arg1, int arg2)&lt;br /&gt;
{&lt;br /&gt;
	sys_log(MODULE_NON, LOG_LEVEL_ERROR, &amp;quot;%s: arg1 = %d, arg2 = %d\n&amp;quot;, (int)__FUNCTION__, arg1, arg2, 0,0,0,0,0,0,0);&lt;br /&gt;
	print_hello();&lt;br /&gt;
&lt;br /&gt;
	return arg1 + arg2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void print_hello(void)&lt;br /&gt;
{&lt;br /&gt;
	fprintf(stderr, &amp;quot;Hello! This is just an example\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
C Header file: Example.h&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void print_hello(void);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CPP Source file: CPP_Example.c&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;CPP_Example.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
extern &amp;quot;C&amp;quot; {&lt;br /&gt;
&lt;br /&gt;
int SHARED_OBJECT_SUB(int arg1, int arg2)&lt;br /&gt;
{&lt;br /&gt;
	print_hello_cpp();&lt;br /&gt;
&lt;br /&gt;
	return arg1 - arg2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
} // extern &amp;quot;C&amp;quot; {&lt;br /&gt;
&lt;br /&gt;
void print_hello_cpp(void)&lt;br /&gt;
{&lt;br /&gt;
	std::cerr &amp;lt;&amp;lt; &amp;quot;A cpp example&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CPP Header file: CPP_Example.h&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void print_hello_cpp(void);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{Note/Important|When declaring function names that will be used from MC-Basic context you must use UPPERCASE letters, as in the example of SHARED_OBJECT_SUM and SHARED_OBJECT_SUB.&amp;lt;br/&amp;gt;User functions must be wrapped with extern &amp;quot;C&amp;quot; to avoid CPP mangled names}}&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
Output strings of functions like printf and fprintf are usually displayed in the Linux terminal, however in the softMC case the behavior is different.&amp;lt;br/&amp;gt;&lt;br /&gt;
The outputs of printf and cout are discarded while output strings of fprintf and cerr are directed to an object called 'nohup' and can later be read by the user.&amp;lt;br/&amp;gt;&lt;br /&gt;
To display the contents of nohup do the following:&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
1. Connect to the softMC using ssh or serial console.&amp;lt;br/&amp;gt;&lt;br /&gt;
2. In the Linux terminal type:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-bash-3.2$ cat /var/home/mc/nohup.out&lt;br /&gt;
....&lt;br /&gt;
....&lt;br /&gt;
Hello! This is just an example&lt;br /&gt;
A cpp example&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
== Getting Compiler ==&lt;br /&gt;
The compiler and linker shall be used in order to build the shared object is defined by the CC variable in the makefile.&amp;lt;br/&amp;gt;&lt;br /&gt;
You would need any linux installation (like Ubuntu) in order to run softMC compiler.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cut and Paste following commands to Linux command line:&amp;lt;br/&amp;gt;&lt;br /&gt;
cd ~&amp;lt;br/&amp;gt;&lt;br /&gt;
wget --no-check-certificate http://servotronix.com/html/softMC_Tool_Chain/0B-jc7OYLo3AYaGFfN2ZkTUNJdHM.tar&amp;lt;br /&amp;gt;&lt;br /&gt;
tar -zxvf 0B-jc7OYLo3AYaGFfN2ZkTUNJdHM.tar&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Complete softMC tool-chain will be installed into your home directory at ~/OSELAS.Toolchain-2011.03.1&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Makefile==&lt;br /&gt;
Please notice that makefle CC variable is assigned with a complete path to gcc compiler. This specific gcc is a part of the tool chain we use to build softMC.&lt;br /&gt;
When compiling shared objects to be linked with softMC it is advised to use OSELAS.Toolchain-2011.03.1 tool chain.&amp;lt;br/&amp;gt;&lt;br /&gt;
The CFLAGS and CPPFLAGS variables in the example might cause compilation errors. It is not advised, but you can remove those that prevent a successful compilation.&lt;br /&gt;
The better option is to fix the compilation errors.&lt;br /&gt;
&lt;br /&gt;
The makefile syntax:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
CC=~/OSELAS.Toolchain-2011.03.1/i586-unknown-linux-gnu/gcc-4.5.2-glibc-2.13-binutils-2.21-kernel-2.6.36-sanitized/bin/i586-unknown-linux-gnu-gcc&lt;br /&gt;
CXX=~/OSELAS.Toolchain-2011.03.1/i586-unknown-linux-gnu/gcc-4.5.2-glibc-2.13-binutils-2.21-kernel-2.6.36-sanitized/bin/i586-unknown-linux-gnu-g++&lt;br /&gt;
CFLAGS=-c -g -ansi -pedantic -Wall -Werror&lt;br /&gt;
CPPFLAGS=-c -g -ansi -pedantic -Wall -Werror&lt;br /&gt;
&lt;br /&gt;
LD_LIBRARY_PATH := .:$(LD_LIBRARY_PATH)&lt;br /&gt;
&lt;br /&gt;
C_SOURCE=Example.c&lt;br /&gt;
CPP_SOURCE=CPP_Example.cpp&lt;br /&gt;
&lt;br /&gt;
C_OBJECTS=$(C_SOURCE:.c=.o)&lt;br /&gt;
CPP_OBJECTS=$(CPP_SOURCE:.cpp=.o)&lt;br /&gt;
&lt;br /&gt;
TARGET=EXAMPLE.O&lt;br /&gt;
&lt;br /&gt;
$(TARGET): $(C_OBJECTS) $(CPP_OBJECTS)&lt;br /&gt;
	$(CC) -shared -o $@ $(C_OBJECTS) $(CPP_OBJECTS)&lt;br /&gt;
&lt;br /&gt;
$(C_OBJECTS): $(C_SOURCE)&lt;br /&gt;
	$(CC) $(CFLAGS) -c $(C_SOURCE)&lt;br /&gt;
&lt;br /&gt;
$(CPP_OBJECTS): $(CPP_SOURCE)&lt;br /&gt;
	$(CXX) $(CPPFLAGS) -c $(CPP_SOURCE)&lt;br /&gt;
&lt;br /&gt;
clean:&lt;br /&gt;
	rm $(C_OBJECTS) $(CPP_OBJECTS) $(TARGET)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order to adapt the makefile to your needs, please change the assignment of the variables 'C_SOURCE' and 'CPP_SOURCE' to the name of the source files in your project, and the assignment of the variable 'TARGET'.&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|softMC can handle only UPPERCASE file names limited to 8.3 convention, meaning, up to 8 characters, followed by a dot, followed by the extensions PRG, or LIB or O (of course in our case it will be .O)&amp;lt;br/&amp;gt;Bear that in mind when assigning the TARGET variable}}&lt;br /&gt;
&lt;br /&gt;
After a successful compilation you will find in the working directory the file EXAMPLE.O, or whatever string was assigned to the variable 'TARGET'.&lt;br /&gt;
&lt;br /&gt;
==copy the shared object to softMC==&lt;br /&gt;
You can copy the shared object to softMC in 2 different ways:&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using scp, copy the file directly to softMC.&amp;lt;br/&amp;gt;&lt;br /&gt;
In the Linux terminal type:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
my_user@my_computer:~/working_directory$ scp EXAMPLE.O mc@mc.ip.add.ress:/FFS0/SSMC&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Where mc.ip.add.ress is the sfotMC's ip address, for example, 192.168.7.152.&amp;lt;br/&amp;gt;&lt;br /&gt;
or&amp;lt;br/&amp;gt;&lt;br /&gt;
2. Use the ControlStudio's file manager to drag and drop the file EXAMPLE.O to the softMC.&lt;br /&gt;
&lt;br /&gt;
==Link the shared object with softMC==&lt;br /&gt;
The shared object now resides within softMC. Now we want to link softMC with the shared object during run-time, and use it.&lt;br /&gt;
Linking the shared object is done with 'oload' command in CONFIG.PRG context.&lt;br /&gt;
Please add to your CONFIG.PRG the line:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
oload EXAMPLE.O&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we need to declare about the shared object's contents and how to use it. This is done by the PROTO.PRO file.&lt;br /&gt;
please add the following lines to your PROTO.PRO file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import_c SHARED_OBJECT_SUM(byval as long, byval as long) as long&lt;br /&gt;
import_c SHARED_OBJECT_SUB(byval as long, byval as long) as long&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Of course, 'SHARED_OBJECT_SUM' is a function implemented in Example.c. You will need to specify the prototypes of your own functions.&amp;lt;br/&amp;gt;&lt;br /&gt;
Using ControlStudio send the edited CONFIG.PRG and PROTO.PRO to softMC and type in the ControlStudio terminal 'reset all'.&lt;br /&gt;
&lt;br /&gt;
If the process was successful, you are now able to invoke functions from the shared object.&lt;br /&gt;
Type in the ControlStudio terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;?SHARED_OBJECT_SUM(5, 6)&lt;br /&gt;
11&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;?SHARED_OBJECT_SUB(5, 6)&lt;br /&gt;
-1&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Passing MC-Basic strings to C functions==&lt;br /&gt;
It is possible to send string objects to C functions for parsing purposes, for example. In order to do so you need to include in your code the following declarations:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
typedef int			INT32;&lt;br /&gt;
typedef unsigned int		UINT32;&lt;br /&gt;
typedef pthread_mutex_t*	SEMM_ID;&lt;br /&gt;
typedef int			FUNCPTR;	/* ptr to func returning int   */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* defining MC Basic SYS String */&lt;br /&gt;
typedef struct {&lt;br /&gt;
	INT32 type;				/* string type */&lt;br /&gt;
	INT32 scope;				/* string variable scope */&lt;br /&gt;
	INT32 temp;				/* memory release flag */&lt;br /&gt;
	INT32 alloc_size;			/* number of bytes allocated */&lt;br /&gt;
	INT32 occup_size;			/* number of bytes occupied */&lt;br /&gt;
	INT32 num_chars;			/* number of characters */&lt;br /&gt;
	UINT32 counter;				/* assignment counter */&lt;br /&gt;
	SEMM_ID mutex;				/* mutex */&lt;br /&gt;
	unsigned char* data;			/* pointer to string */&lt;br /&gt;
	FUNCPTR FuncUpdateString;		/* pointer to callback function */&lt;br /&gt;
	INT32 FuncUpdateStringParam;		/* parameter of callback function */&lt;br /&gt;
} SYS_STRING;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the declaration of the C function that receives the string, specify the string argument:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int MY_C_FUNCTION(int some_var, SYS_STRING* some_str)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In the import_c command that declares the interface from MC-Basic to C function, declare:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
import_c MY_C_FUNCTION(byval as long, byval as string) as long&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using Linux sys.log from Shared Object context==&lt;br /&gt;
It is possible to log messages in the Linux logger sys.log. In order to do so you need to include in your code the following declarations:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/**************************    Linux sys.log Declarations    ******************************/&lt;br /&gt;
&lt;br /&gt;
/* MC Modules */&lt;br /&gt;
#define MODULE_NON	 	 0&lt;br /&gt;
#define MODULE_MOTION		 1&lt;br /&gt;
#define MODULE_RTS		 2&lt;br /&gt;
#define MODULE_TRANSLAT		 3&lt;br /&gt;
#define MODULE_SERCOS		 4&lt;br /&gt;
#define MODULE_ROBOT		 5&lt;br /&gt;
#define MODULE_TRACER		 6&lt;br /&gt;
#define MODULE_SYSTEM		 7&lt;br /&gt;
#define MODULE_MEMORY		 8&lt;br /&gt;
#define MODULE_FILE_SYSTEM	 9&lt;br /&gt;
#define MODULE_CLI		10&lt;br /&gt;
#define MODULE_RBOOTP		11&lt;br /&gt;
#define MODULE_ETHERCAT		12&lt;br /&gt;
#define MODULE_FASTDATA		13&lt;br /&gt;
#define MODULE_UAC		14&lt;br /&gt;
#define MODULE_MC_BASIC		15&lt;br /&gt;
#define MODULE_CANOPEN		16&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* MC Log Level */&lt;br /&gt;
#define LOG_LEVEL_NON		0&lt;br /&gt;
#define LOG_LEVEL_ERROR		1&lt;br /&gt;
#define LOG_LEVEL_WARNING	2&lt;br /&gt;
#define LOG_LEVEL_NOTE		3&lt;br /&gt;
#define LOG_LEVEL_DEBUG		4&lt;br /&gt;
#define LOG_LEVEL_ALL		5&lt;br /&gt;
&lt;br /&gt;
extern int sys_log(int sub_system, int _debug_level, const char * fmt, int arg1, int arg2,&lt;br /&gt;
			int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10);&lt;br /&gt;
&lt;br /&gt;
/******************************************************************************************/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To send a message to sys.log invoke sys_log with fmt as a printf formatted string.&lt;br /&gt;
A more thorough explanation about sys.log and an example can be found in [[Program_Examples:sys_log|Linux sys.log]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
Extract Shared_Object.ZIP to find the above examples&amp;lt;br/&amp;gt;&lt;br /&gt;
[[File:Shared_Object.zip||Shared_Object.zip]]&lt;br /&gt;
&lt;br /&gt;
The example corresponds to commit SHA-1: 5228016ac44122213dcb05d781b15c8e05054d5b in GIT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
* [[MC-Basic_C-Interface|MC-Basic C-Interface]]&lt;br /&gt;
* [[MC-Basic:IMPORT_C|IMPORT_C]]&lt;br /&gt;
* [[Program_Examples:sys_log|Linux sys.log]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Program_Examples:Shared_Objects&amp;diff=125553</id>
		<title>Program Examples:Shared Objects</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Program_Examples:Shared_Objects&amp;diff=125553"/>
				<updated>2015-08-04T09:54:29Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The following example demonstrates how to compile a shared object in Linux and link it with softMC at run-time.&lt;br /&gt;
&lt;br /&gt;
Below there are 5 example files: A C source file, a C header file, a CPP source file, a CPP header file and a makefile.&amp;lt;br/&amp;gt;&lt;br /&gt;
The source and header files implement a simple program that is given 2 integers as arguments and returns their sum or difference.&amp;lt;br/&amp;gt;&lt;br /&gt;
This program DOESN'T include a main function, therefore the program can be compiled only into a library, and not an executable.&lt;br /&gt;
&lt;br /&gt;
==Example Program==&lt;br /&gt;
C Source file: Example.c&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;Example.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
/**************************    Linux sys.log Declarations    ******************************/&lt;br /&gt;
&lt;br /&gt;
/* MC Modules */&lt;br /&gt;
#define MODULE_NON	 	 0&lt;br /&gt;
#define MODULE_MOTION		 1&lt;br /&gt;
#define MODULE_RTS		 2&lt;br /&gt;
#define MODULE_TRANSLAT		 3&lt;br /&gt;
#define MODULE_SERCOS		 4&lt;br /&gt;
#define MODULE_ROBOT		 5&lt;br /&gt;
#define MODULE_TRACER		 6&lt;br /&gt;
#define MODULE_SYSTEM		 7&lt;br /&gt;
#define MODULE_MEMORY		 8&lt;br /&gt;
#define MODULE_FILE_SYSTEM	 9&lt;br /&gt;
#define MODULE_CLI		10&lt;br /&gt;
#define MODULE_RBOOTP		11&lt;br /&gt;
#define MODULE_ETHERCAT		12&lt;br /&gt;
#define MODULE_FASTDATA		13&lt;br /&gt;
#define MODULE_UAC		14&lt;br /&gt;
#define MODULE_MC_BASIC		15&lt;br /&gt;
#define MODULE_CANOPEN		16&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* MC Log Level */&lt;br /&gt;
#define LOG_LEVEL_NON		0&lt;br /&gt;
#define LOG_LEVEL_ERROR		1&lt;br /&gt;
#define LOG_LEVEL_WARNING	2&lt;br /&gt;
#define LOG_LEVEL_NOTE		3&lt;br /&gt;
#define LOG_LEVEL_DEBUG		4&lt;br /&gt;
#define LOG_LEVEL_ALL		5&lt;br /&gt;
&lt;br /&gt;
extern int sys_log(int sub_system, int _debug_level, const char * fmt, int arg1, int arg2,&lt;br /&gt;
			int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10);&lt;br /&gt;
&lt;br /&gt;
/******************************************************************************************/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int SHARED_OBJECT_SUM(int arg1, int arg2)&lt;br /&gt;
{&lt;br /&gt;
	sys_log(MODULE_NON, LOG_LEVEL_ERROR, &amp;quot;%s: arg1 = %d, arg2 = %d\n&amp;quot;, (int)__FUNCTION__, arg1, arg2, 0,0,0,0,0,0,0);&lt;br /&gt;
	print_hello();&lt;br /&gt;
&lt;br /&gt;
	return arg1 + arg2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void print_hello(void)&lt;br /&gt;
{&lt;br /&gt;
	fprintf(stderr, &amp;quot;Hello! This is just an example\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
C Header file: Example.h&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void print_hello(void);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CPP Source file: CPP_Example.c&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;CPP_Example.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
extern &amp;quot;C&amp;quot; {&lt;br /&gt;
&lt;br /&gt;
int SHARED_OBJECT_SUB(int arg1, int arg2)&lt;br /&gt;
{&lt;br /&gt;
	print_hello_cpp();&lt;br /&gt;
&lt;br /&gt;
	return arg1 - arg2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
} // extern &amp;quot;C&amp;quot; {&lt;br /&gt;
&lt;br /&gt;
void print_hello_cpp(void)&lt;br /&gt;
{&lt;br /&gt;
	std::cerr &amp;lt;&amp;lt; &amp;quot;A cpp example&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CPP Header file: CPP_Example.h&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void print_hello_cpp(void);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{Note/Important|When declaring function names that will be used from MC-Basic context you must use UPPERCASE letters, as in the example of SHARED_OBJECT_SUM and SHARED_OBJECT_SUB.&amp;lt;br/&amp;gt;User functions must be wrapped with extern &amp;quot;C&amp;quot; to avoid CPP mangled names}}&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
Output strings of functions like printf and fprintf are usually displayed in the Linux terminal, however in the softMC case the behavior is different.&amp;lt;br/&amp;gt;&lt;br /&gt;
The outputs of printf and cout are discarded while output strings of fprintf and cerr are directed to an object called 'nohup' and can later be read by the user.&amp;lt;br/&amp;gt;&lt;br /&gt;
To display the contents of nohup do the following:&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
1. Connect to the softMC using ssh or serial console.&amp;lt;br/&amp;gt;&lt;br /&gt;
2. In the Linux terminal type:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-bash-3.2$ cat /var/home/mc/nohup.out&lt;br /&gt;
....&lt;br /&gt;
....&lt;br /&gt;
Hello! This is just an example&lt;br /&gt;
A cpp example&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
== Getting Compiler ==&lt;br /&gt;
The compiler and linker shall be used in order to build the shared object is defined by the CC variable in the makefile.&amp;lt;br/&amp;gt;&lt;br /&gt;
You would need any linux installation (like Ubuntu) in order to run softMC compiler.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cut and Paste following commands to Linux command line:&amp;lt;br/&amp;gt;&lt;br /&gt;
cd ~&amp;lt;br/&amp;gt;&lt;br /&gt;
wget --no-check-certificate http://servotronix.com/html/softMC_Tool_Chain/0B-jc7OYLo3AYaGFfN2ZkTUNJdHM.tar&amp;lt;br /&amp;gt;&lt;br /&gt;
tar -zxvf 0B-jc7OYLo3AYaGFfN2ZkTUNJdHM.tar&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Complete softMC tool-chain will be installed into your home directory at ~/OSELAS.Toolchain-2011.03.1&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Makefile==&lt;br /&gt;
Please notice that makefle CC variable is assigned with a complete path to gcc compiler. This specific gcc is a part of the tool chain we use to build softMC.&lt;br /&gt;
When compiling shared objects to be linked with softMC it is advised to use OSELAS.Toolchain-2011.03.1 tool chain.&amp;lt;br/&amp;gt;&lt;br /&gt;
The CFLAGS and CPPFLAGS variables in the example might cause compilation errors. It is not advised, but you can remove those that prevent a successful compilation.&lt;br /&gt;
The better option is to fix the compilation errors.&lt;br /&gt;
&lt;br /&gt;
The makefile syntax:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
CC=~/OSELAS.Toolchain-2011.03.1/i586-unknown-linux-gnu/gcc-4.5.2-glibc-2.13-binutils-2.21-kernel-2.6.36-sanitized/bin/i586-unknown-linux-gnu-gcc&lt;br /&gt;
CXX=~/OSELAS.Toolchain-2011.03.1/i586-unknown-linux-gnu/gcc-4.5.2-glibc-2.13-binutils-2.21-kernel-2.6.36-sanitized/bin/i586-unknown-linux-gnu-g++&lt;br /&gt;
CFLAGS=-c -g -ansi -pedantic -Wall -Werror&lt;br /&gt;
CPPFLAGS=-c -g -ansi -pedantic -Wall -Werror&lt;br /&gt;
&lt;br /&gt;
LD_LIBRARY_PATH := .:$(LD_LIBRARY_PATH)&lt;br /&gt;
&lt;br /&gt;
C_SOURCE=Example.c&lt;br /&gt;
CPP_SOURCE=CPP_Example.cpp&lt;br /&gt;
&lt;br /&gt;
C_OBJECTS=$(C_SOURCE:.c=.o)&lt;br /&gt;
CPP_OBJECTS=$(CPP_SOURCE:.cpp=.o)&lt;br /&gt;
&lt;br /&gt;
TARGET=EXAMPLE.O&lt;br /&gt;
&lt;br /&gt;
$(TARGET): $(C_OBJECTS) $(CPP_OBJECTS)&lt;br /&gt;
	$(CC) -shared -o $@ $(C_OBJECTS) $(CPP_OBJECTS)&lt;br /&gt;
&lt;br /&gt;
$(C_OBJECTS): $(C_SOURCE)&lt;br /&gt;
	$(CC) $(CFLAGS) -c $(C_SOURCE)&lt;br /&gt;
&lt;br /&gt;
$(CPP_OBJECTS): $(CPP_SOURCE)&lt;br /&gt;
	$(CXX) $(CPPFLAGS) -c $(CPP_SOURCE)&lt;br /&gt;
&lt;br /&gt;
clean:&lt;br /&gt;
	rm $(C_OBJECTS) $(CPP_OBJECTS) $(TARGET)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order to adapt the makefile to your needs, please change the assignment of the variables 'C_SOURCE' and 'CPP_SOURCE' to the name of the source files in your project, and the assignment of the variable 'TARGET'.&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|softMC can handle only UPPERCASE file names limited to 8.3 convention, meaning, up to 8 characters, followed by a dot, followed by the extensions PRG, or LIB or O (of course in our case it will be .O)&amp;lt;br/&amp;gt;Bear that in mind when assigning the TARGET variable}}&lt;br /&gt;
&lt;br /&gt;
After a successful compilation you will find in the working directory the file EXAMPLE.O, or whatever string was assigned to the variable 'TARGET'.&lt;br /&gt;
&lt;br /&gt;
==copy the shared object to softMC==&lt;br /&gt;
You can copy the shared object to softMC in 2 different ways:&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using scp, copy the file directly to softMC.&amp;lt;br/&amp;gt;&lt;br /&gt;
In the Linux terminal type:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
my_user@my_computer:~/working_directory$ scp EXAMPLE.O mc@mc.ip.add.ress:/FFS0/SSMC&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Where mc.ip.add.ress is the sfotMC's ip address, for example, 192.168.7.152.&amp;lt;br/&amp;gt;&lt;br /&gt;
or&amp;lt;br/&amp;gt;&lt;br /&gt;
2. Use the ControlStudio's file manager to drag and drop the file EXAMPLE.O to the softMC.&lt;br /&gt;
&lt;br /&gt;
==Link the shared object with softMC==&lt;br /&gt;
The shared object now resides within softMC. Now we want to link softMC with the shared object during run-time, and use it.&lt;br /&gt;
Linking the shared object is done with 'oload' command in CONFIG.PRG context.&lt;br /&gt;
Please add to your CONFIG.PRG the line:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
oload EXAMPLE.O&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we need to declare about the shared object's contents and how to use it. This is done by the PROTO.PRO file.&lt;br /&gt;
please add the following lines to your PROTO.PRO file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import_c SHARED_OBJECT_SUM(byval as long, byval as long) as long&lt;br /&gt;
import_c SHARED_OBJECT_SUB(byval as long, byval as long) as long&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Of course, 'SHARED_OBJECT_SUM' is a function implemented in Example.c. You will need to specify the prototypes of your own functions.&amp;lt;br/&amp;gt;&lt;br /&gt;
Using ControlStudio send the edited CONFIG.PRG and PROTO.PRO to softMC and type in the ControlStudio terminal 'reset all'.&lt;br /&gt;
&lt;br /&gt;
If the process was successful, you are now able to invoke functions from the shared object.&lt;br /&gt;
Type in the ControlStudio terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;?SHARED_OBJECT_SUM(5, 6)&lt;br /&gt;
11&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;?SHARED_OBJECT_SUB(5, 6)&lt;br /&gt;
-1&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Passing MC-Basic strings to C functions==&lt;br /&gt;
It is possible to send string objects to C functions for parsing purposes, for example. In order to do so you need to include in your code the following declarations:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
typedef int			INT32;&lt;br /&gt;
typedef unsigned int		UINT32;&lt;br /&gt;
typedef pthread_mutex_t*	SEMM_ID;&lt;br /&gt;
typedef int			FUNCPTR;	/* ptr to func returning int   */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* defining MC Basic SYS String */&lt;br /&gt;
typedef struct {&lt;br /&gt;
	INT32 type;				/* string type */&lt;br /&gt;
	INT32 scope;				/* string variable scope */&lt;br /&gt;
	INT32 temp;				/* memory release flag */&lt;br /&gt;
	INT32 alloc_size;			/* number of bytes allocated */&lt;br /&gt;
	INT32 occup_size;			/* number of bytes occupied */&lt;br /&gt;
	INT32 num_chars;			/* number of characters */&lt;br /&gt;
	UINT32 counter;				/* assignment counter */&lt;br /&gt;
	SEMM_ID mutex;				/* mutex */&lt;br /&gt;
	unsigned char* data;			/* pointer to string */&lt;br /&gt;
	FUNCPTR FuncUpdateString;		/* pointer to callback function */&lt;br /&gt;
	INT32 FuncUpdateStringParam;		/* parameter of callback function */&lt;br /&gt;
} SYS_STRING;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the declaration of the C function that receives the string, specify the string argument:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int MY_C_FUNCTION(int some_var, SYS_STRING* some_str)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In the import_c command that declares the interface from MC-Basic to C function, declare:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
import_c MY_C_FUNCTION(byval as long, byval as string) as long&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Using Linux sys.log from Shared Object context==&lt;br /&gt;
It is possible to log messages in the Linux logger sys.log. In order to do so you need to include in your code the following declarations:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/**************************    Linux sys.log Declarations    ******************************/&lt;br /&gt;
&lt;br /&gt;
/* MC Modules */&lt;br /&gt;
#define MODULE_NON	 	 0&lt;br /&gt;
#define MODULE_MOTION		 1&lt;br /&gt;
#define MODULE_RTS		 2&lt;br /&gt;
#define MODULE_TRANSLAT		 3&lt;br /&gt;
#define MODULE_SERCOS		 4&lt;br /&gt;
#define MODULE_ROBOT		 5&lt;br /&gt;
#define MODULE_TRACER		 6&lt;br /&gt;
#define MODULE_SYSTEM		 7&lt;br /&gt;
#define MODULE_MEMORY		 8&lt;br /&gt;
#define MODULE_FILE_SYSTEM	 9&lt;br /&gt;
#define MODULE_CLI		10&lt;br /&gt;
#define MODULE_RBOOTP		11&lt;br /&gt;
#define MODULE_ETHERCAT		12&lt;br /&gt;
#define MODULE_FASTDATA		13&lt;br /&gt;
#define MODULE_UAC		14&lt;br /&gt;
#define MODULE_MC_BASIC		15&lt;br /&gt;
#define MODULE_CANOPEN		16&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* MC Log Level */&lt;br /&gt;
#define LOG_LEVEL_NON		0&lt;br /&gt;
#define LOG_LEVEL_ERROR		1&lt;br /&gt;
#define LOG_LEVEL_WARNING	2&lt;br /&gt;
#define LOG_LEVEL_NOTE		3&lt;br /&gt;
#define LOG_LEVEL_DEBUG		4&lt;br /&gt;
#define LOG_LEVEL_ALL		5&lt;br /&gt;
&lt;br /&gt;
extern int sys_log(int sub_system, int _debug_level, const char * fmt, int arg1, int arg2,&lt;br /&gt;
			int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10);&lt;br /&gt;
&lt;br /&gt;
/******************************************************************************************/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To send a message to sys.log invoke sys_log with fmt as a printf formatted string.&lt;br /&gt;
A more thorough explanation about sys.log and an example can be found in [[Program_Examples:sys_log|Linux sys.log]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
Extract Shared_Object.ZIP to find the above examples&amp;lt;br/&amp;gt;&lt;br /&gt;
[[File:Shared_Object.zip||Shared_Object.zip]]&lt;br /&gt;
&lt;br /&gt;
The example corresponds to commit SHA-1: 5228016ac44122213dcb05d781b15c8e05054d5b in GIT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
* [[MC-Basic:IMPORT_C|IMPORT_C]]&lt;br /&gt;
* [[Program_Examples:sys_log|Linux sys.log]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Program_Examples:Shared_Objects&amp;diff=125552</id>
		<title>Program Examples:Shared Objects</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Program_Examples:Shared_Objects&amp;diff=125552"/>
				<updated>2015-08-04T09:51:35Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The following example demonstrates how to compile a shared object in Linux and link it with softMC at run-time.&lt;br /&gt;
&lt;br /&gt;
Below there are 5 example files: A C source file, a C header file, a CPP source file, a CPP header file and a makefile.&amp;lt;br/&amp;gt;&lt;br /&gt;
The source and header files implement a simple program that is given 2 integers as arguments and returns their sum or difference.&amp;lt;br/&amp;gt;&lt;br /&gt;
This program DOESN'T include a main function, therefore the program can be compiled only into a library, and not an executable.&lt;br /&gt;
&lt;br /&gt;
==Example Program==&lt;br /&gt;
C Source file: Example.c&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;Example.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
/**************************    Linux sys.log Declarations    ******************************/&lt;br /&gt;
&lt;br /&gt;
/* MC Modules */&lt;br /&gt;
#define MODULE_NON	 	 0&lt;br /&gt;
#define MODULE_MOTION		 1&lt;br /&gt;
#define MODULE_RTS		 2&lt;br /&gt;
#define MODULE_TRANSLAT		 3&lt;br /&gt;
#define MODULE_SERCOS		 4&lt;br /&gt;
#define MODULE_ROBOT		 5&lt;br /&gt;
#define MODULE_TRACER		 6&lt;br /&gt;
#define MODULE_SYSTEM		 7&lt;br /&gt;
#define MODULE_MEMORY		 8&lt;br /&gt;
#define MODULE_FILE_SYSTEM	 9&lt;br /&gt;
#define MODULE_CLI		10&lt;br /&gt;
#define MODULE_RBOOTP		11&lt;br /&gt;
#define MODULE_ETHERCAT		12&lt;br /&gt;
#define MODULE_FASTDATA		13&lt;br /&gt;
#define MODULE_UAC		14&lt;br /&gt;
#define MODULE_MC_BASIC		15&lt;br /&gt;
#define MODULE_CANOPEN		16&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* MC Log Level */&lt;br /&gt;
#define LOG_LEVEL_NON		0&lt;br /&gt;
#define LOG_LEVEL_ERROR		1&lt;br /&gt;
#define LOG_LEVEL_WARNING	2&lt;br /&gt;
#define LOG_LEVEL_NOTE		3&lt;br /&gt;
#define LOG_LEVEL_DEBUG		4&lt;br /&gt;
#define LOG_LEVEL_ALL		5&lt;br /&gt;
&lt;br /&gt;
extern int sys_log(int sub_system, int _debug_level, const char * fmt, int arg1, int arg2,&lt;br /&gt;
			int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10);&lt;br /&gt;
&lt;br /&gt;
/******************************************************************************************/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int SHARED_OBJECT_SUM(int arg1, int arg2)&lt;br /&gt;
{&lt;br /&gt;
	sys_log(MODULE_NON, LOG_LEVEL_ERROR, &amp;quot;%s: arg1 = %d, arg2 = %d\n&amp;quot;, (int)__FUNCTION__, arg1, arg2, 0,0,0,0,0,0,0);&lt;br /&gt;
	print_hello();&lt;br /&gt;
&lt;br /&gt;
	return arg1 + arg2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void print_hello(void)&lt;br /&gt;
{&lt;br /&gt;
	fprintf(stderr, &amp;quot;Hello! This is just an example\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
C Header file: Example.h&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void print_hello(void);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CPP Source file: CPP_Example.c&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;CPP_Example.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
extern &amp;quot;C&amp;quot; {&lt;br /&gt;
&lt;br /&gt;
int SHARED_OBJECT_SUB(int arg1, int arg2)&lt;br /&gt;
{&lt;br /&gt;
	print_hello_cpp();&lt;br /&gt;
&lt;br /&gt;
	return arg1 - arg2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
} // extern &amp;quot;C&amp;quot; {&lt;br /&gt;
&lt;br /&gt;
void print_hello_cpp(void)&lt;br /&gt;
{&lt;br /&gt;
	std::cerr &amp;lt;&amp;lt; &amp;quot;A cpp example&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CPP Header file: CPP_Example.h&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void print_hello_cpp(void);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{Note/Important|When declaring function names that will be used from MC-Basic context you must use UPPERCASE letters, as in the example of SHARED_OBJECT_SUM and SHARED_OBJECT_SUB.&amp;lt;br/&amp;gt;User functions must be wrapped with extern &amp;quot;C&amp;quot; to avoid CPP mangled names}}&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
Output strings of functions like printf and fprintf are usually displayed in the Linux terminal, however in the softMC case the behavior is different.&amp;lt;br/&amp;gt;&lt;br /&gt;
The outputs of printf and cout are discarded while output strings of fprintf and cerr are directed to an object called 'nohup' and can later be read by the user.&amp;lt;br/&amp;gt;&lt;br /&gt;
To display the contents of nohup do the following:&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
1. Connect to the softMC using ssh or serial console.&amp;lt;br/&amp;gt;&lt;br /&gt;
2. In the Linux terminal type:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-bash-3.2$ cat /var/home/mc/nohup.out&lt;br /&gt;
....&lt;br /&gt;
....&lt;br /&gt;
Hello! This is just an example&lt;br /&gt;
A cpp example&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
== Getting Compiler ==&lt;br /&gt;
The compiler and linker shall be used in order to build the shared object is defined by the CC variable in the makefile.&amp;lt;br/&amp;gt;&lt;br /&gt;
You would need any linux installation (like Ubuntu) in order to run softMC compiler.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cut and Paste following commands to Linux command line:&amp;lt;br/&amp;gt;&lt;br /&gt;
cd ~&amp;lt;br/&amp;gt;&lt;br /&gt;
wget --no-check-certificate http://servotronix.com/html/softMC_Tool_Chain/0B-jc7OYLo3AYaGFfN2ZkTUNJdHM.tar&amp;lt;br /&amp;gt;&lt;br /&gt;
tar -zxvf 0B-jc7OYLo3AYaGFfN2ZkTUNJdHM.tar&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Complete softMC tool-chain will be installed into your home directory at ~/OSELAS.Toolchain-2011.03.1&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Makefile==&lt;br /&gt;
Please notice that makefle CC variable is assigned with a complete path to gcc compiler. This specific gcc is a part of the tool chain we use to build softMC.&lt;br /&gt;
When compiling shared objects to be linked with softMC it is advised to use OSELAS.Toolchain-2011.03.1 tool chain.&amp;lt;br/&amp;gt;&lt;br /&gt;
The CFLAGS and CPPFLAGS variables in the example might cause compilation errors. It is not advised, but you can remove those that prevent a successful compilation.&lt;br /&gt;
The better option is to fix the compilation errors.&lt;br /&gt;
&lt;br /&gt;
The makefile syntax:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
CC=~/OSELAS.Toolchain-2011.03.1/i586-unknown-linux-gnu/gcc-4.5.2-glibc-2.13-binutils-2.21-kernel-2.6.36-sanitized/bin/i586-unknown-linux-gnu-gcc&lt;br /&gt;
CXX=~/OSELAS.Toolchain-2011.03.1/i586-unknown-linux-gnu/gcc-4.5.2-glibc-2.13-binutils-2.21-kernel-2.6.36-sanitized/bin/i586-unknown-linux-gnu-g++&lt;br /&gt;
CFLAGS=-c -g -ansi -pedantic -Wall -Werror&lt;br /&gt;
CPPFLAGS=-c -g -ansi -pedantic -Wall -Werror&lt;br /&gt;
&lt;br /&gt;
LD_LIBRARY_PATH := .:$(LD_LIBRARY_PATH)&lt;br /&gt;
&lt;br /&gt;
C_SOURCE=Example.c&lt;br /&gt;
CPP_SOURCE=CPP_Example.cpp&lt;br /&gt;
&lt;br /&gt;
C_OBJECTS=$(C_SOURCE:.c=.o)&lt;br /&gt;
CPP_OBJECTS=$(CPP_SOURCE:.cpp=.o)&lt;br /&gt;
&lt;br /&gt;
TARGET=EXAMPLE.O&lt;br /&gt;
&lt;br /&gt;
$(TARGET): $(C_OBJECTS) $(CPP_OBJECTS)&lt;br /&gt;
	$(CC) -shared -o $@ $(C_OBJECTS) $(CPP_OBJECTS)&lt;br /&gt;
&lt;br /&gt;
$(C_OBJECTS): $(C_SOURCE)&lt;br /&gt;
	$(CC) $(CFLAGS) -c $(C_SOURCE)&lt;br /&gt;
&lt;br /&gt;
$(CPP_OBJECTS): $(CPP_SOURCE)&lt;br /&gt;
	$(CXX) $(CPPFLAGS) -c $(CPP_SOURCE)&lt;br /&gt;
&lt;br /&gt;
clean:&lt;br /&gt;
	rm $(C_OBJECTS) $(CPP_OBJECTS) $(TARGET)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order to adapt the makefile to your needs, please change the assignment of the variables 'C_SOURCE' and 'CPP_SOURCE' to the name of the source files in your project, and the assignment of the variable 'TARGET'.&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|softMC can handle only UPPERCASE file names limited to 8.3 convention, meaning, up to 8 characters, followed by a dot, followed by the extensions PRG, or LIB or O (of course in our case it will be .O)&amp;lt;br/&amp;gt;Bear that in mind when assigning the TARGET variable}}&lt;br /&gt;
&lt;br /&gt;
After a successful compilation you will find in the working directory the file EXAMPLE.O, or whatever string was assigned to the variable 'TARGET'.&lt;br /&gt;
&lt;br /&gt;
==copy the shared object to softMC==&lt;br /&gt;
You can copy the shared object to softMC in 2 different ways:&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using scp, copy the file directly to softMC.&amp;lt;br/&amp;gt;&lt;br /&gt;
In the Linux terminal type:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
my_user@my_computer:~/working_directory$ scp EXAMPLE.O mc@mc.ip.add.ress:/FFS0/SSMC&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Where mc.ip.add.ress is the sfotMC's ip address, for example, 192.168.7.152.&amp;lt;br/&amp;gt;&lt;br /&gt;
or&amp;lt;br/&amp;gt;&lt;br /&gt;
2. Use the ControlStudio's file manager to drag and drop the file EXAMPLE.O to the softMC.&lt;br /&gt;
&lt;br /&gt;
==Link the shared object with softMC==&lt;br /&gt;
The shared object now resides within softMC. Now we want to link softMC with the shared object during run-time, and use it.&lt;br /&gt;
Linking the shared object is done with 'oload' command in CONFIG.PRG context.&lt;br /&gt;
Please add to your CONFIG.PRG the line:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
oload EXAMPLE.O&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we need to declare about the shared object's contents and how to use it. This is done by the PROTO.PRO file.&lt;br /&gt;
please add the following lines to your PROTO.PRO file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import_c SHARED_OBJECT_SUM(byval as long, byval as long) as long&lt;br /&gt;
import_c SHARED_OBJECT_SUB(byval as long, byval as long) as long&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Of course, 'SHARED_OBJECT_SUM' is a function implemented in Example.c. You will need to specify the prototypes of your own functions.&amp;lt;br/&amp;gt;&lt;br /&gt;
Using ControlStudio send the edited CONFIG.PRG and PROTO.PRO to softMC and type in the ControlStudio terminal 'reset all'.&lt;br /&gt;
&lt;br /&gt;
If the process was successful, you are now able to invoke functions from the shared object.&lt;br /&gt;
Type in the ControlStudio terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;?SHARED_OBJECT_SUM(5, 6)&lt;br /&gt;
11&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;?SHARED_OBJECT_SUB(5, 6)&lt;br /&gt;
-1&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Passing MC-Basic strings to C functions==&lt;br /&gt;
It is possible to send string objects to C functions for parsing purposes, for example. In order to do so you need to include in your code the following declarations:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
typedef int			INT32;&lt;br /&gt;
typedef unsigned int		UINT32;&lt;br /&gt;
typedef pthread_mutex_t*	SEMM_ID;&lt;br /&gt;
typedef int	FUNCPTR;	/* ptr to func returning int   */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* defining MC Basic SYS String only for the sake of receiving IP address over string when using ModBus TCP */&lt;br /&gt;
typedef struct {&lt;br /&gt;
	INT32 type;				/* string type */&lt;br /&gt;
	INT32 scope;				/* string variable scope */&lt;br /&gt;
	INT32 temp;				/* memory release flag */&lt;br /&gt;
	INT32 alloc_size;			/* number of bytes allocated */&lt;br /&gt;
	INT32 occup_size;			/* number of bytes occupied */&lt;br /&gt;
	INT32 num_chars;			/* number of characters */&lt;br /&gt;
	UINT32 counter;				/* assignment counter */&lt;br /&gt;
	SEMM_ID mutex;				/* mutex */&lt;br /&gt;
	unsigned char* data;			/* pointer to string */&lt;br /&gt;
	FUNCPTR FuncUpdateString;		/* pointer to callback function */&lt;br /&gt;
	INT32 FuncUpdateStringParam;		/* parameter of callback function */&lt;br /&gt;
} SYS_STRING;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using Linux sys.log from Shared Object context==&lt;br /&gt;
It is possible to log messages in the Linux logger sys.log. In order to do so you need to include in your code the following declarations:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/**************************    Linux sys.log Declarations    ******************************/&lt;br /&gt;
&lt;br /&gt;
/* MC Modules */&lt;br /&gt;
#define MODULE_NON	 	 0&lt;br /&gt;
#define MODULE_MOTION		 1&lt;br /&gt;
#define MODULE_RTS		 2&lt;br /&gt;
#define MODULE_TRANSLAT		 3&lt;br /&gt;
#define MODULE_SERCOS		 4&lt;br /&gt;
#define MODULE_ROBOT		 5&lt;br /&gt;
#define MODULE_TRACER		 6&lt;br /&gt;
#define MODULE_SYSTEM		 7&lt;br /&gt;
#define MODULE_MEMORY		 8&lt;br /&gt;
#define MODULE_FILE_SYSTEM	 9&lt;br /&gt;
#define MODULE_CLI		10&lt;br /&gt;
#define MODULE_RBOOTP		11&lt;br /&gt;
#define MODULE_ETHERCAT		12&lt;br /&gt;
#define MODULE_FASTDATA		13&lt;br /&gt;
#define MODULE_UAC		14&lt;br /&gt;
#define MODULE_MC_BASIC		15&lt;br /&gt;
#define MODULE_CANOPEN		16&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* MC Log Level */&lt;br /&gt;
#define LOG_LEVEL_NON		0&lt;br /&gt;
#define LOG_LEVEL_ERROR		1&lt;br /&gt;
#define LOG_LEVEL_WARNING	2&lt;br /&gt;
#define LOG_LEVEL_NOTE		3&lt;br /&gt;
#define LOG_LEVEL_DEBUG		4&lt;br /&gt;
#define LOG_LEVEL_ALL		5&lt;br /&gt;
&lt;br /&gt;
extern int sys_log(int sub_system, int _debug_level, const char * fmt, int arg1, int arg2,&lt;br /&gt;
			int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10);&lt;br /&gt;
&lt;br /&gt;
/******************************************************************************************/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To send a message to sys.log invoke sys_log with fmt as a printf formatted string.&lt;br /&gt;
A more thorough explanation about sys.log and an example can be found in [[Program_Examples:sys_log|Linux sys.log]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
Extract Shared_Object.ZIP to find the above examples&amp;lt;br/&amp;gt;&lt;br /&gt;
[[File:Shared_Object.zip||Shared_Object.zip]]&lt;br /&gt;
&lt;br /&gt;
The example corresponds to commit SHA-1: 5228016ac44122213dcb05d781b15c8e05054d5b in GIT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
* [[MC-Basic:IMPORT_C|IMPORT_C]]&lt;br /&gt;
* [[Program_Examples:sys_log|Linux sys.log]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	<entry>
		<id>http://softmc.servotronix.com/index.php?title=Program_Examples:Shared_Objects&amp;diff=125551</id>
		<title>Program Examples:Shared Objects</title>
		<link rel="alternate" type="text/html" href="http://softmc.servotronix.com/index.php?title=Program_Examples:Shared_Objects&amp;diff=125551"/>
				<updated>2015-08-04T09:50:23Z</updated>
		
		<summary type="html">&lt;p&gt;Nigeller: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The following example demonstrates how to compile a shared object in Linux and link it with softMC at run-time.&lt;br /&gt;
&lt;br /&gt;
Below there are 5 example files: A C source file, a C header file, a CPP source file, a CPP header file and a makefile.&amp;lt;br/&amp;gt;&lt;br /&gt;
The source and header files implement a simple program that is given 2 integers as arguments and returns their sum or difference.&amp;lt;br/&amp;gt;&lt;br /&gt;
This program DOESN'T include a main function, therefore the program can be compiled only into a library, and not an executable.&lt;br /&gt;
&lt;br /&gt;
==Example Program==&lt;br /&gt;
C Source file: Example.c&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;Example.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
/**************************    Linux sys.log Declarations    ******************************/&lt;br /&gt;
&lt;br /&gt;
/* MC Modules */&lt;br /&gt;
#define MODULE_NON	 	 0&lt;br /&gt;
#define MODULE_MOTION		 1&lt;br /&gt;
#define MODULE_RTS		 2&lt;br /&gt;
#define MODULE_TRANSLAT		 3&lt;br /&gt;
#define MODULE_SERCOS		 4&lt;br /&gt;
#define MODULE_ROBOT		 5&lt;br /&gt;
#define MODULE_TRACER		 6&lt;br /&gt;
#define MODULE_SYSTEM		 7&lt;br /&gt;
#define MODULE_MEMORY		 8&lt;br /&gt;
#define MODULE_FILE_SYSTEM	 9&lt;br /&gt;
#define MODULE_CLI		10&lt;br /&gt;
#define MODULE_RBOOTP		11&lt;br /&gt;
#define MODULE_ETHERCAT		12&lt;br /&gt;
#define MODULE_FASTDATA		13&lt;br /&gt;
#define MODULE_UAC		14&lt;br /&gt;
#define MODULE_MC_BASIC		15&lt;br /&gt;
#define MODULE_CANOPEN		16&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* MC Log Level */&lt;br /&gt;
#define LOG_LEVEL_NON		0&lt;br /&gt;
#define LOG_LEVEL_ERROR		1&lt;br /&gt;
#define LOG_LEVEL_WARNING	2&lt;br /&gt;
#define LOG_LEVEL_NOTE		3&lt;br /&gt;
#define LOG_LEVEL_DEBUG		4&lt;br /&gt;
#define LOG_LEVEL_ALL		5&lt;br /&gt;
&lt;br /&gt;
extern int sys_log(int sub_system, int _debug_level, const char * fmt, int arg1, int arg2,&lt;br /&gt;
			int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10);&lt;br /&gt;
&lt;br /&gt;
/******************************************************************************************/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int SHARED_OBJECT_SUM(int arg1, int arg2)&lt;br /&gt;
{&lt;br /&gt;
	sys_log(MODULE_NON, LOG_LEVEL_ERROR, &amp;quot;%s: arg1 = %d, arg2 = %d\n&amp;quot;, (int)__FUNCTION__, arg1, arg2, 0,0,0,0,0,0,0);&lt;br /&gt;
	print_hello();&lt;br /&gt;
&lt;br /&gt;
	return arg1 + arg2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void print_hello(void)&lt;br /&gt;
{&lt;br /&gt;
	fprintf(stderr, &amp;quot;Hello! This is just an example\n&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
C Header file: Example.h&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void print_hello(void);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CPP Source file: CPP_Example.c&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;CPP_Example.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
extern &amp;quot;C&amp;quot; {&lt;br /&gt;
&lt;br /&gt;
int SHARED_OBJECT_SUB(int arg1, int arg2)&lt;br /&gt;
{&lt;br /&gt;
	print_hello_cpp();&lt;br /&gt;
&lt;br /&gt;
	return arg1 - arg2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
} // extern &amp;quot;C&amp;quot; {&lt;br /&gt;
&lt;br /&gt;
void print_hello_cpp(void)&lt;br /&gt;
{&lt;br /&gt;
	std::cerr &amp;lt;&amp;lt; &amp;quot;A cpp example&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CPP Header file: CPP_Example.h&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void print_hello_cpp(void);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{Note/Important|When declaring function names that will be used from MC-Basic context you must use UPPERCASE letters, as in the example of SHARED_OBJECT_SUM and SHARED_OBJECT_SUB.&amp;lt;br/&amp;gt;User functions must be wrapped with extern &amp;quot;C&amp;quot; to avoid CPP mangled names}}&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
Output strings of functions like printf and fprintf are usually displayed in the Linux terminal, however in the softMC case the behavior is different.&amp;lt;br/&amp;gt;&lt;br /&gt;
The outputs of printf and cout are discarded while output strings of fprintf and cerr are directed to an object called 'nohup' and can later be read by the user.&amp;lt;br/&amp;gt;&lt;br /&gt;
To display the contents of nohup do the following:&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
1. Connect to the softMC using ssh or serial console.&amp;lt;br/&amp;gt;&lt;br /&gt;
2. In the Linux terminal type:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-bash-3.2$ cat /var/home/mc/nohup.out&lt;br /&gt;
....&lt;br /&gt;
....&lt;br /&gt;
Hello! This is just an example&lt;br /&gt;
A cpp example&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
== Getting Compiler ==&lt;br /&gt;
The compiler and linker shall be used in order to build the shared object is defined by the CC variable in the makefile.&amp;lt;br/&amp;gt;&lt;br /&gt;
You would need any linux installation (like Ubuntu) in order to run softMC compiler.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cut and Paste following commands to Linux command line:&amp;lt;br/&amp;gt;&lt;br /&gt;
cd ~&amp;lt;br/&amp;gt;&lt;br /&gt;
wget --no-check-certificate http://servotronix.com/html/softMC_Tool_Chain/0B-jc7OYLo3AYaGFfN2ZkTUNJdHM.tar&amp;lt;br /&amp;gt;&lt;br /&gt;
tar -zxvf 0B-jc7OYLo3AYaGFfN2ZkTUNJdHM.tar&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Complete softMC tool-chain will be installed into your home directory at ~/OSELAS.Toolchain-2011.03.1&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Makefile==&lt;br /&gt;
Please notice that makefle CC variable is assigned with a complete path to gcc compiler. This specific gcc is a part of the tool chain we use to build softMC.&lt;br /&gt;
When compiling shared objects to be linked with softMC it is advised to use OSELAS.Toolchain-2011.03.1 tool chain.&amp;lt;br/&amp;gt;&lt;br /&gt;
The CFLAGS and CPPFLAGS variables in the example might cause compilation errors. It is not advised, but you can remove those that prevent a successful compilation.&lt;br /&gt;
The better option is to fix the compilation errors.&lt;br /&gt;
&lt;br /&gt;
The makefile syntax:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
CC=~/OSELAS.Toolchain-2011.03.1/i586-unknown-linux-gnu/gcc-4.5.2-glibc-2.13-binutils-2.21-kernel-2.6.36-sanitized/bin/i586-unknown-linux-gnu-gcc&lt;br /&gt;
CXX=~/OSELAS.Toolchain-2011.03.1/i586-unknown-linux-gnu/gcc-4.5.2-glibc-2.13-binutils-2.21-kernel-2.6.36-sanitized/bin/i586-unknown-linux-gnu-g++&lt;br /&gt;
CFLAGS=-c -g -ansi -pedantic -Wall -Werror&lt;br /&gt;
CPPFLAGS=-c -g -ansi -pedantic -Wall -Werror&lt;br /&gt;
&lt;br /&gt;
LD_LIBRARY_PATH := .:$(LD_LIBRARY_PATH)&lt;br /&gt;
&lt;br /&gt;
C_SOURCE=Example.c&lt;br /&gt;
CPP_SOURCE=CPP_Example.cpp&lt;br /&gt;
&lt;br /&gt;
C_OBJECTS=$(C_SOURCE:.c=.o)&lt;br /&gt;
CPP_OBJECTS=$(CPP_SOURCE:.cpp=.o)&lt;br /&gt;
&lt;br /&gt;
TARGET=EXAMPLE.O&lt;br /&gt;
&lt;br /&gt;
$(TARGET): $(C_OBJECTS) $(CPP_OBJECTS)&lt;br /&gt;
	$(CC) -shared -o $@ $(C_OBJECTS) $(CPP_OBJECTS)&lt;br /&gt;
&lt;br /&gt;
$(C_OBJECTS): $(C_SOURCE)&lt;br /&gt;
	$(CC) $(CFLAGS) -c $(C_SOURCE)&lt;br /&gt;
&lt;br /&gt;
$(CPP_OBJECTS): $(CPP_SOURCE)&lt;br /&gt;
	$(CXX) $(CPPFLAGS) -c $(CPP_SOURCE)&lt;br /&gt;
&lt;br /&gt;
clean:&lt;br /&gt;
	rm $(C_OBJECTS) $(CPP_OBJECTS) $(TARGET)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In order to adapt the makefile to your needs, please change the assignment of the variables 'C_SOURCE' and 'CPP_SOURCE' to the name of the source files in your project, and the assignment of the variable 'TARGET'.&lt;br /&gt;
&lt;br /&gt;
{{Note/Important|softMC can handle only UPPERCASE file names limited to 8.3 convention, meaning, up to 8 characters, followed by a dot, followed by the extensions PRG, or LIB or O (of course in our case it will be .O)&amp;lt;br/&amp;gt;Bear that in mind when assigning the TARGET variable}}&lt;br /&gt;
&lt;br /&gt;
After a successful compilation you will find in the working directory the file EXAMPLE.O, or whatever string was assigned to the variable 'TARGET'.&lt;br /&gt;
&lt;br /&gt;
==copy the shared object to softMC==&lt;br /&gt;
You can copy the shared object to softMC in 2 different ways:&amp;lt;br/&amp;gt;&lt;br /&gt;
1. Using scp, copy the file directly to softMC.&amp;lt;br/&amp;gt;&lt;br /&gt;
In the Linux terminal type:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
my_user@my_computer:~/working_directory$ scp EXAMPLE.O mc@mc.ip.add.ress:/FFS0/SSMC&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Where mc.ip.add.ress is the sfotMC's ip address, for example, 192.168.7.152.&amp;lt;br/&amp;gt;&lt;br /&gt;
or&amp;lt;br/&amp;gt;&lt;br /&gt;
2. Use the ControlStudio's file manager to drag and drop the file EXAMPLE.O to the softMC.&lt;br /&gt;
&lt;br /&gt;
==Link the shared object with softMC==&lt;br /&gt;
The shared object now resides within softMC. Now we want to link softMC with the shared object during run-time, and use it.&lt;br /&gt;
Linking the shared object is done with 'oload' command in CONFIG.PRG context.&lt;br /&gt;
Please add to your CONFIG.PRG the line:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
oload EXAMPLE.O&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we need to declare about the shared object's contents and how to use it. This is done by the PROTO.PRO file.&lt;br /&gt;
please add the following lines to your PROTO.PRO file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import_c SHARED_OBJECT_SUM(byval as long, byval as long) as long&lt;br /&gt;
import_c SHARED_OBJECT_SUB(byval as long, byval as long) as long&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Of course, 'SHARED_OBJECT_SUM' is a function implemented in Example.c. You will need to specify the prototypes of your own functions.&amp;lt;br/&amp;gt;&lt;br /&gt;
Using ControlStudio send the edited CONFIG.PRG and PROTO.PRO to softMC and type in the ControlStudio terminal 'reset all'.&lt;br /&gt;
&lt;br /&gt;
If the process was successful, you are now able to invoke functions from the shared object.&lt;br /&gt;
Type in the ControlStudio terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;?SHARED_OBJECT_SUM(5, 6)&lt;br /&gt;
11&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
--&amp;gt;?SHARED_OBJECT_SUB(5, 6)&lt;br /&gt;
-1&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Passing MC-Basic strings to C functions==&lt;br /&gt;
It is possible to send string objects to C functions for parsing purposes, for example. In order to do so you need to include in your code the following declarations:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
typedef int             INT32;&lt;br /&gt;
typedef unsigned int    UINT32;&lt;br /&gt;
typedef pthread_mutex_t* SEMM_ID;&lt;br /&gt;
typedef int    FUNCPTR;       /* ptr to func returning int   */&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* defining MC Basic SYS String only for the sake of receiving IP address over string when using ModBus TCP */&lt;br /&gt;
typedef struct {&lt;br /&gt;
	INT32 type;				/* string type */&lt;br /&gt;
	INT32 scope;				/* string variable scope */&lt;br /&gt;
	INT32 temp;				/* memory release flag */&lt;br /&gt;
	INT32 alloc_size;			/* number of bytes allocated */&lt;br /&gt;
	INT32 occup_size;			/* number of bytes occupied */&lt;br /&gt;
	INT32 num_chars;			/* number of characters */&lt;br /&gt;
	UINT32 counter;				/* assignment counter */&lt;br /&gt;
	SEMM_ID mutex;				/* mutex */&lt;br /&gt;
	unsigned char* data;			/* pointer to string */&lt;br /&gt;
	FUNCPTR FuncUpdateString;		/* pointer to callback function */&lt;br /&gt;
	INT32 FuncUpdateStringParam;		/* parameter of callback function */&lt;br /&gt;
} SYS_STRING;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Using Linux sys.log from Shared Object context==&lt;br /&gt;
It is possible to log messages in the Linux logger sys.log. In order to do so you need to include in your code the following declarations:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/**************************    Linux sys.log Declarations    ******************************/&lt;br /&gt;
&lt;br /&gt;
/* MC Modules */&lt;br /&gt;
#define MODULE_NON	 	 0&lt;br /&gt;
#define MODULE_MOTION		 1&lt;br /&gt;
#define MODULE_RTS		 2&lt;br /&gt;
#define MODULE_TRANSLAT		 3&lt;br /&gt;
#define MODULE_SERCOS		 4&lt;br /&gt;
#define MODULE_ROBOT		 5&lt;br /&gt;
#define MODULE_TRACER		 6&lt;br /&gt;
#define MODULE_SYSTEM		 7&lt;br /&gt;
#define MODULE_MEMORY		 8&lt;br /&gt;
#define MODULE_FILE_SYSTEM	 9&lt;br /&gt;
#define MODULE_CLI		10&lt;br /&gt;
#define MODULE_RBOOTP		11&lt;br /&gt;
#define MODULE_ETHERCAT		12&lt;br /&gt;
#define MODULE_FASTDATA		13&lt;br /&gt;
#define MODULE_UAC		14&lt;br /&gt;
#define MODULE_MC_BASIC		15&lt;br /&gt;
#define MODULE_CANOPEN		16&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/* MC Log Level */&lt;br /&gt;
#define LOG_LEVEL_NON		0&lt;br /&gt;
#define LOG_LEVEL_ERROR		1&lt;br /&gt;
#define LOG_LEVEL_WARNING	2&lt;br /&gt;
#define LOG_LEVEL_NOTE		3&lt;br /&gt;
#define LOG_LEVEL_DEBUG		4&lt;br /&gt;
#define LOG_LEVEL_ALL		5&lt;br /&gt;
&lt;br /&gt;
extern int sys_log(int sub_system, int _debug_level, const char * fmt, int arg1, int arg2,&lt;br /&gt;
			int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10);&lt;br /&gt;
&lt;br /&gt;
/******************************************************************************************/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To send a message to sys.log invoke sys_log with fmt as a printf formatted string.&lt;br /&gt;
A more thorough explanation about sys.log and an example can be found in [[Program_Examples:sys_log|Linux sys.log]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
Extract Shared_Object.ZIP to find the above examples&amp;lt;br/&amp;gt;&lt;br /&gt;
[[File:Shared_Object.zip||Shared_Object.zip]]&lt;br /&gt;
&lt;br /&gt;
The example corresponds to commit SHA-1: 5228016ac44122213dcb05d781b15c8e05054d5b in GIT.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
* [[MC-Basic:IMPORT_C|IMPORT_C]]&lt;br /&gt;
* [[Program_Examples:sys_log|Linux sys.log]]&lt;/div&gt;</summary>
		<author><name>Nigeller</name></author>	</entry>

	</feed>