jackvoxel8.com Posted February 23, 2018 Posted February 23, 2018 I have a Power Brick controller with an RS-232 port. It the documentation it says: "In general, this port should not be used to communicate to external peripherals, but rather left in case of the need to debug." Which tells me there is _some_ way to actually use it to communicate with external devices. Does anyone have experience doing this?
steve.milici Posted February 23, 2018 Posted February 23, 2018 Yes – see this application note on the Forums’ FileDepot: “http://forums.deltatau.com/filedepot/download.php?f=Power PMAC/Application Notes/Serial Communication with Power PMAC in C.pdf”
jackvoxel8.com Posted February 27, 2018 Author Posted February 27, 2018 I am getting the following error both when I paste in your link and when I manually navigate to the PDF through the filedepot "File does not exist. Make sure you specified correct file name."
jackvoxel8.com Posted February 27, 2018 Author Posted February 27, 2018 Ok for some reason it worked today when I tried to download it. Thanks for the pointer this looks like exactly what I need.
jackvoxel8.com Posted April 2, 2018 Author Posted April 2, 2018 Hi Steve, I have succeeded in getting my serial device connected to my power pmac controller. I can run my C Background Program if I go to the Task Manager, select the PLC tab, fund my application and click "Start". After doing this I can see the expected output from my serial device in the Unsolicited Messages. Ideally I would have this C program constantly running and dumping the latest serial message into a variable (my serial device is a laser distance sensor). Then from a motion program or normal PLC I could just read this variable to get the latest distance reading from my attached serial device. Is this possible? Do I have to worry about locking to precent reading from the variable at the same time my program is writing to it? Would it be OK to have this C background program running on essentially an infinite loop? I would like to keep the serial device open and not open/close for every reading. Here is the current background program: // Includes #include // Global Gp Shared memory pointer #include "../../Include/pp_proj.h" #include "../../Libraries/serialportcomm/serialportcomm.h" #include // Global Rt/Gp Shared memory pointers // Definitions // Can change this if you expect a longer response from the serial device #define EXAMPLE_CODE_RESPONSE_MAX 256 // Prototype(s) int ReadExampleDevice(char *Port); // This is the main executable location int main(void) { InitLibrary(); ReadExampleDevice(USB1_Port); CloseLibrary(); return 0; } //************************* // Application code snippet //************************* // Global Variables int SerialPort; // This routine will break into Linux scheduling when called. // USB serial ports use the Linux scheduler, not Xenomai RTOS. // Nothing that needs complete determinism should call this routine. int ReadExampleDevice(char *Port) { static const char *SampleCommand = "%01#RMD**\r"; char msg[EXAMPLE_CODE_RESPONSE_MAX]; int ret; // Initialize the serial port. // "/dev/ttyUSB0" is where Power PMAC maps the USB-to-Serial device // The second number is the baud rate. Here are some example baud rates: // B9600: 9600 baud // B38400: 38400 baud (the default for talking to a Turbo PMAC) // B115200: 115200 baud (the default for talking to a host PC or to another Power PMAC) SerialPort = OpenSerialPort(Port,B38400); // Change your baud rate to what you need. To talk to Turbo PMAC, use 38400. // Note: If you want to use this to talk to Turbo PMAC, I1 should be set to 1 on the PMAC to disable CS handshaking // Otherwise, Turbo will wait until it gets the CS signal to send characters //Check return code to see if the port opened properly. if(SerialPort < 0) { Send(1, "Problem opening port!"); return SerialPort; } else printf("Serial port opened properly.\n"); //Write out the command to read display on meter... ret = write(SerialPort, SampleCommand, strlen(SampleCommand)); //If write() does not return the requested number of bytes to write, we have a problem. //Pass return code on to the calling routine. if(ret != strlen(SampleCommand)) { Send(1, "Problem writing to port!"); // Send to PPMAC's Send1 port return ret; } //Read back the string into the "msg" buffer... ret = ReadSerialLine(msg, EXAMPLE_CODE_RESPONSE_MAX, '\n', SerialPort, 10.000); if(ret) { Send(1, "Did not get a response from port!"); // Send to PPMAC's Send1 port return ret; } //Echo Response to Power PMAC send port Send(1, "Response:"); // Send to PPMAC's Send1 port Send(1, msg); // Send to PPMAC's Send1 port close(SerialPort); return 0; // All went well; return good status code. }
Clopedandle Posted April 2, 2018 Posted April 2, 2018 You can do this. Just make sure to put nanosleep() in your infinite loop, or you'll watchdog the PPMAC. You should also create a break condition variable so you can stop the program when you want. You can write your message to a global variable for convenience. First, assign these globals in your global definitions.pmh file; something like: global MySerialPortMessage, MyBreakConditionVariable = 0.0; Then, in your C program, you can make a loop like so: while(pshm->P[MyBreakConditionVariable] < 1.0) { //Write out the command to read display on meter... ret = write(SerialPort, SampleCommand, strlen(SampleCommand)); //If write() does not return the requested number of bytes to write, we have a problem. //Pass return code on to the calling routine. if(ret != strlen(SampleCommand)) { Send(1, "Problem writing to port!"); // Send to PPMAC's Send1 port return ret; } //Read back the string into the "msg" buffer... ret = ReadSerialLine(msg, EXAMPLE_CODE_RESPONSE_MAX, '\n', SerialPort, 10.000); if(ret) { Send(1, "Did not get a response from port!"); // Send to PPMAC's Send1 port return ret; } pshm->P[MySerialPortMessage] = atof(msg); MySleepSec(0.1); // sec } Where void MySleepSec(double SleepTimeSeconds) { struct timespec Timer; Timer = Sec2TimeSpec(SleepTimeSeconds); nanosleep(&Timer,NULL); } and struct timespec Sec2TimeSpec(double TimeSec) { struct timespec Timer; Timer.tv_sec = (long int)TimeSec; Timer.tv_nsec = (long int)((TimeSec-(double)Timer.tv_sec)*1000000000.0); return Timer; } To break your loop, just write MyBreakConditionVariable=1 from any program or the Terminal window.
jackvoxel8.com Posted April 3, 2018 Author Posted April 3, 2018 Thank you Clopedandle, this is exactly what I was looking for. I can confirm it is working for me. I have a few more questions about background programs: 1) Using your method I can stop the program from another program by writing to the break condition variable. Is there any way for me to start the program from another program? (I am currently using the Task Manager to start it) Similarly, is it possible for me to query the current Running/NotRunning status? 2) I see you used the "pshm->P[GlobalVar]" to read and write Global variables. What is the difference between using that and the "SetGlobalVar" and "GetGlobalVar" functions? 3) How low can I safely push the time in "MySleepSec"? (currently set to 0.1) 4) Do I have to worry about reading a corrupt value of the global var from another program or are reading/write atomic?
Clopedandle Posted April 4, 2018 Posted April 4, 2018 You're welcome. 1. To start the program (assuming it's capp1.out) from a PLC, you can issue system "/var/ftp/usrflash/Project/C\ Language/Background\ Programs/capp1.out"; from another C program, use popen() or fork() and the path: /var/ftp/usrflash/Project/C\ Language/Background\ Programs/capp1.out 2. pshm->P[] and Set/GetGlobalVar are fundamentally the same. I prefer the syntax of the former. 3. I think you could safely push it to 0.001, although it may be pointless if your serial device is not providing data that fast. You can always try setting it that low and checking Task Manager to see if your CPU usage is going too high. 4. I believe it is atomic, but cannot remember completely. Perhaps a member of the ODT staff could answer? Curt?
curtwilson Posted April 4, 2018 Posted April 4, 2018 Accesses to global variables are atomic, so this is not a concern.
Recommended Posts