library for C++ CANOpen implementation. mbed independant, but is easy to attach into with mbed.
Dependents: ppCANOpen_Example DISCO-F746NG_rtos_test
Example:
Import programppCANOpen_Example
I am no longer actively working on the ppCANOpen library, however, I want to publish this project so that anyone who wants to pick up any of the pieces can have a good example. This is a a project I was working on using the ppCANOpen library. It has a pretty in deep use of the object dictionary structure. And a number of functions to control high voltage pinball drivers, if you're into that sort of thing.
source/ServiceProvider.cpp
- Committer:
- ptpaterson
- Date:
- 2016-02-13
- Revision:
- 5:22a337cdc0e3
- Parent:
- 4:2034b04c86d2
File content as of revision 5:22a337cdc0e3:
/**
******************************************************************************
* @file
* @author Paul Paterson
* @version
* @date 2015-12-22
* @brief CANOpen implementation library
******************************************************************************
* @attention
*
* <h2><center>© COPYRIGHT(c) 2015 Paul Paterson
*
* All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mbed.h"
#include "ServiceProvider.h"
#include "Node.h"
#include "canopen_api.h"
#include <string.h>
#include <stdio.h>
namespace ppCANOpen
{
ServiceProvider::ServiceProvider (void) : nodeCount(0)
{
bInboxUnlocked = 1;
//memset (nodes, 0, sizeof(Node) * SERVICE_MAX_NODES ); // TODO: fix incorrect <--
for (int i = 0; i < SERVICE_MAX_NODES; i++) {
nodes[i] = 0;
}
CanOpenApiInit((void *)this, &ReadIT_CWrapper, &UpdateNodes_CWrapper);
}
ServiceProvider::~ServiceProvider (void)
{
}
/* ============================================================================
* Public Methods
* ============================================================================
*/
/* Main application ---------------------------------------------------------*/
void ServiceProvider::Run (void)
{
//while (1) {
/* Check for new messages.
* Dispatch one at a time in order for nodes to handle incoming data
*/
bInboxUnlocked = 0;
if (! inbox.empty()) {
/* Handle things inside of Service Provider first if necessary */
if (CANOPEN_FUNCTION_CODE_TIME == MESSAGE_GET_COMMAND(inbox.front().id)) {
HandleTimeMessage(&inbox.front());
} else {
/* Send out remaining messages to the Nodes */
// TODO if time stamp message, then the SP can sync the clock for all nodes
/* if new message exists, give it to the nodes*/
for (int i=0; i < nodeCount; i++) {
nodes[i]->DispatchMessage(&inbox.front());
}
}
inbox.pop();
}
bInboxUnlocked = 1;
/* Update all of the nodes */
for (int i=0; i < nodeCount; i++) {
nodes[i]->Update();
}
/* send out the responses */
while (! outbox.empty()) {
if (CanOpenApiWrite(&outbox.front().message)) {
/* send message externally first.
* Since we want to keep the message alive and try to resend, we
* do not want to keep resending the message internally over and
* over again.*/
/* dispatch to the internal nodes */
for (int i=0; i < nodeCount; i++) {
if ((nodes[i]->bLoopbackOn) ||
(nodes[i]->nodeId != outbox.front().nodeId)) {
nodes[i]->DispatchMessage(&outbox.front().message);
}
}
outbox.pop();
} else {
printf("Could not send last message. Trying again\r\n");
}
}
wait (.005);
//}
}
void ServiceProvider::UpdateNodes(void)
{
uint32_t time = GetTime();
//printf("S::Run() update nodes\r\n");
/* update all of the nodes */
for (int i=0; i < nodeCount; i++) {
nodes[i]->FixedUpdate(time);
}
}
void ServiceProvider::UpdateNodes_CWrapper(void *pServiceObject)
{
ServiceProvider * pTempProvider = static_cast <ServiceProvider *> (pServiceObject);
pTempProvider->UpdateNodes();
}
/* Node Management ----------------------------------------------------------*/
int ServiceProvider::AddNode (Node * node)
{
int result = 1;
if (nodeCount < SERVICE_MAX_NODES) {
nodes[nodeCount++] = node;
} else {
result = 0;
}
return result;
}
/* CanMessage Transmission --------------------------------------------------*/
void ServiceProvider::PostMessage (int nodeId, CanOpenMessage * msg)
{
outbox.push(InternalMessage(nodeId, *msg));
}
void ServiceProvider::PostNmtControl (char targetNodeId, NmtCommandSpecifier cs)
{
CanOpenMessage msg;
msg.id = 0;
msg.dataCount = 2;
msg.type = CANOPEN_TYPE_DATA;
msg.format = CANOPEN_FORMAT_STANDARD;
// NOTE: memcpy is freezing execution
//memcpy(msg.data, canMsg.data, canMsg.len);
msg.data[0] = targetNodeId;
msg.data[1] = (char) cs;
//msg.data[2] =
//msg.data[3] =
//msg.data[4] =
//msg.data[5] =
//msg.data[6] =
//msg.data[7] =
PostMessage(0, &msg);
}
/* ============================================================================
* Private Methods
* ============================================================================
*/
/* CanMessage Reading -------------------------------------------------------*/
void ServiceProvider::ReadIT(void)
{
//printf("S::ReadIT()\r\n");
CanOpenMessage msg;
if(CanOpenApiRead (&msg)) {
if (bInboxUnlocked) {
ReadIT_clearBuffer();
inbox.push(msg);
} else {
inboxBuffer.push(msg);
printf("!!!!!!!!!!!!!!!!!!!!!!!INBOX LOCKED!!!!!!!!!!!!!!!!!!!!!!!!!!!\r\n");
}
}
}
void ServiceProvider::ReadIT_clearBuffer(void)
{
while (! inboxBuffer.empty()) {
inbox.push (inboxBuffer.front());
inboxBuffer.pop();
}
}
void ServiceProvider::ReadIT_CWrapper(void *pServiceObject)
{
ServiceProvider * pTempProvider = static_cast <ServiceProvider *> (pServiceObject);
pTempProvider->ReadIT();
}
/* Elapsed Time -------------------------------------------------------------*/
uint32_t ServiceProvider::GetTime(void)
{
return (CanOpenApiGetHardwareTime() + elapsedTimeOffset) & 0x0FFFFFFF;
}
void ServiceProvider::HandleTimeMessage(CanOpenMessage *canOpenMsg)
{
if (6 == canOpenMsg->dataCount) {
uint32_t timeStamp_ms = (uint32_t)canOpenMsg->data[0] +
(uint32_t)canOpenMsg->data[1] << 8 +
(uint32_t)canOpenMsg->data[2] << 16 +
(uint32_t)canOpenMsg->data[3] << 24;
// Nothing uses Days yet, going to ignore for now.
// uint32_t timeStamp_days = (uint32_t)canOpenMsg->data[4] +
// (uint32_t)canOpenMsg->data[5] << 8;
uint32_t hwTime = CanOpenApiGetHardwareTime() & 0x0FFFFFFF;
elapsedTimeOffset = ((int32_t)timeStamp_ms) - ((int32_t)hwTime);
// Else TODO: send error
}
}
} /* namspace ppCANOpen */
