-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added C++ Example with ported CheesyVisionServer #1
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||
<?fileVersion 4.0.0?> | ||
|
||
<cproject> | ||
<storageModule moduleId="org.eclipse.cdt.core.settings"> | ||
<cconfiguration id="org.eclipse.cdt.core.default.config.283967106"> | ||
<storageModule buildSystemId="org.eclipse.cdt.core.defaultConfigDataProvider" id="org.eclipse.cdt.core.default.config.283967106" moduleId="org.eclipse.cdt.core.settings" name="Configuration"> | ||
<externalSettings/> | ||
<extensions> | ||
<extension id="com.windriver.ide.core.WRScannerInfoProvider" point="org.eclipse.cdt.core.ScannerInfoProvider"/> | ||
<extension id="com.windriver.ide.core.WRElfParserVxWorks" point="org.eclipse.cdt.core.BinaryParser"/> | ||
<extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/> | ||
</extensions> | ||
</storageModule> | ||
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> | ||
<storageModule moduleId="org.eclipse.cdt.core.pathentry"> | ||
<pathentry kind="src" path=""/> | ||
<pathentry kind="out" path=""/> | ||
<pathentry kind="con" path="com.windriver.ide.core.WR_CONTAINER"/> | ||
<pathentry kind="con" path="com.windriver.ide.core.build.model.WR_USERDEFINED_CONTAINER"/> | ||
</storageModule> | ||
<storageModule moduleId="scannerConfiguration"/> | ||
<storageModule moduleId="userdefinedContainer"> | ||
<indexAllFiles value="false"/> | ||
<initialized value="true"/> | ||
</storageModule> | ||
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/> | ||
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/> | ||
</cconfiguration> | ||
</storageModule> | ||
</cproject> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<projectDescription> | ||
<name>CheesyVisionRobot</name> | ||
<comment></comment> | ||
<projects> | ||
</projects> | ||
<buildSpec> | ||
<buildCommand> | ||
<name>com.windriver.ide.core.wrbuilder</name> | ||
<arguments> | ||
</arguments> | ||
</buildCommand> | ||
</buildSpec> | ||
<natures> | ||
<nature>com.windriver.ide.core.wrnature</nature> | ||
<nature>com.windriver.ide.core.wrcorenature</nature> | ||
<nature>org.eclipse.cdt.core.cnature</nature> | ||
<nature>org.eclipse.cdt.core.ccnature</nature> | ||
</natures> | ||
</projectDescription> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# The file ".wrmakefile" is the template used by the Wind River Workbench to | ||
# generate the makefiles of this project. Add user-specific build targets and | ||
# make rules only(!) in this project's ".wrmakefile" file. These will then be | ||
# automatically dumped into the makefiles. | ||
|
||
WIND_HOME := $(subst \,/,$(WIND_HOME)) | ||
WIND_BASE := $(subst \,/,$(WIND_BASE)) | ||
WIND_USR := $(subst \,/,$(WIND_USR)) | ||
|
||
all : pre_build main_all post_build | ||
|
||
_clean :: | ||
@echo "make: removing targets and objects of `pwd`" | ||
|
||
%IDE_GENERATED% | ||
|
||
-include $(PRJ_ROOT_DIR)/*.makefile | ||
|
||
-include *.makefile | ||
|
||
main_all : external_build $(PROJECT_TARGETS) | ||
@echo "make: built targets of `pwd`" | ||
|
||
# entry point for extending the build | ||
external_build :: | ||
@echo "" | ||
|
||
# main entry point for pre processing prior to the build | ||
pre_build :: $(PRE_BUILD_STEP) generate_sources | ||
@echo "" | ||
|
||
# entry point for generating sources prior to the build | ||
generate_sources :: | ||
@echo "" | ||
|
||
# main entry point for post processing after the build | ||
post_build :: $(POST_BUILD_STEP) deploy_output | ||
@echo "" | ||
|
||
# entry point for deploying output after the build | ||
deploy_output :: | ||
@echo "" | ||
|
||
clean :: external_clean $(CLEAN_STEP) _clean | ||
|
||
# entry point for extending the build clean | ||
external_clean :: | ||
@echo "" |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
#include "WPILib.h" | ||
#include "CheesyVisionServer.h" | ||
|
||
class CheesyVisionRobot : public IterativeRobot | ||
{ | ||
CheesyVisionServer *server; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your indentation is inconsistent... Please explicitly make private members private. class { private: |
||
public: | ||
static const int listenPort = 1180; | ||
CheesyVisionRobot() | ||
{ | ||
server = CheesyVisionServer::GetInstance(); | ||
} | ||
|
||
void CheesyVisionRobot::RobotInit() { | ||
server->SetPort(listenPort); | ||
server->StartListening(); | ||
} | ||
|
||
void CheesyVisionRobot::DisabledInit() { | ||
server->StopSamplingCounts(); | ||
} | ||
|
||
void CheesyVisionRobot::DisabledPeriodic() { | ||
|
||
} | ||
|
||
void CheesyVisionRobot::AutonomousInit() { | ||
server->Reset(); | ||
server->StartSamplingCounts(); | ||
} | ||
|
||
void CheesyVisionRobot::AutonomousPeriodic() { | ||
printf("Left Status: %d\tRight Status: %d\n", server->GetLeftStatus(), server->GetRightStatus()); | ||
printf("Left Counts: %d\tRight Counts: %d\tTotal Count: %d", server->GetLeftCount(), server->GetRightCount(), server->GetTotalCount()); | ||
} | ||
|
||
void CheesyVisionRobot::TeleopInit() { | ||
} | ||
|
||
void CheesyVisionRobot::TeleopPeriodic() { | ||
} | ||
|
||
void CheesyVisionRobot::TestInit() { | ||
} | ||
|
||
void CheesyVisionRobot::TestPeriodic() { | ||
} | ||
|
||
}; | ||
|
||
START_ROBOT_CLASS(CheesyVisionRobot); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
#include "CheesyVisionServer.h" | ||
#include "WPILib.h" | ||
#include "networktables2/util/EOFException.h" | ||
|
||
CheesyVisionServer *CheesyVisionServer::_instance = (CheesyVisionServer *) 0; | ||
|
||
#define HEARTBEAT_TIMEOUT 3.0 | ||
|
||
CheesyVisionServer::CheesyVisionServer(int port) | ||
{ | ||
_listenPort = port; | ||
_counting = false; | ||
_curLeftStatus = false; | ||
_curRightStatus = false; | ||
_lastHeartbeatTime = Timer::GetFPGATimestamp(); | ||
_leftCount = 0; | ||
_rightCount = 0; | ||
_totalCount = 0; | ||
_listening = false; | ||
|
||
|
||
} | ||
|
||
void CheesyVisionServer::Run() | ||
{ | ||
if (_listening == false) return; //Make sure we are listening | ||
|
||
SocketServerStreamProvider *sock; | ||
sock = new SocketServerStreamProvider(_listenPort); | ||
while (_listening) | ||
{ | ||
IOStream *stream = sock->accept(); | ||
_lastHeartbeatTime = Timer::GetFPGATimestamp(); | ||
try | ||
{ | ||
while (Timer::GetFPGATimestamp() < _lastHeartbeatTime + HEARTBEAT_TIMEOUT) | ||
{ | ||
try | ||
{ | ||
uint8_t byte; | ||
stream->read(&byte, 1); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please document this command better. Under exactly what conditions does it return a EOFException? Looks like it returns one after 1 second of not receiving any data. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. EOFException is returned by the SocketServerStreamProvider when the end of the stream has been reached and another read is performed |
||
_curLeftStatus = (byte & (1 << 1)) > 0; | ||
_curRightStatus = (byte & (1 << 0)) > 0; | ||
UpdateCounts(_curLeftStatus,_curRightStatus); | ||
_lastHeartbeatTime = Timer::GetFPGATimestamp(); | ||
} | ||
catch (EOFException e) | ||
{ | ||
//End of file, wait for a bit and read some more | ||
|
||
Wait(0.05); | ||
} | ||
|
||
} | ||
} | ||
catch (IOException e) | ||
{ | ||
printf("Socket IO error: %s\n", e.what()); | ||
//Catching this exception will dro | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. will ... ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. drop the current connection and create a new one |
||
} | ||
delete stream;//close, delete and recreate the stream | ||
|
||
Wait(0.05); | ||
} | ||
delete sock; | ||
} | ||
|
||
void CheesyVisionServer::Reset() | ||
{ | ||
_leftCount = 0; | ||
_rightCount = 0; | ||
_totalCount = 0; | ||
|
||
_curLeftStatus = false; | ||
_curRightStatus = false; | ||
} | ||
|
||
void CheesyVisionServer::UpdateCounts(bool left, bool right) | ||
{ | ||
if (true == _counting) | ||
{ | ||
_leftCount += left ? 1 : 0; | ||
_rightCount += right ? 1 : 0; | ||
_totalCount++; | ||
} | ||
} | ||
|
||
CheesyVisionServer *CheesyVisionServer::GetInstance() | ||
{ | ||
if (CheesyVisionServer::_instance == (CheesyVisionServer *) 0) | ||
{ | ||
CheesyVisionServer::_instance = new CheesyVisionServer(); | ||
} | ||
return CheesyVisionServer::_instance; | ||
} | ||
|
||
bool CheesyVisionServer::HasClientConnection() | ||
{ | ||
return (_lastHeartbeatTime > 0) && (Timer::GetFPGATimestamp() - _lastHeartbeatTime); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Huh? lastHeartbeatTime is initialized to the FPGA timestamp |
||
} | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
#include "jankyTask.h" | ||
#include "networktables2/stream/SocketServerStreamProvider.h" | ||
|
||
#ifndef CHEESYVISIONSERVER_H_ | ||
#define CHEESYVISIONSERVER_H_ | ||
|
||
|
||
|
||
class CheesyVisionServer: private JankyTask | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Private inheritance! Noooooo.... |
||
{ | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I want to see a comment for each line in this file at a minimum. What does everything do? |
||
static CheesyVisionServer *_instance; | ||
|
||
|
||
CheesyVisionServer(int port = 1180); | ||
int _listenPort; | ||
|
||
int _leftCount; | ||
int _rightCount; | ||
int _totalCount; | ||
bool _curLeftStatus; | ||
bool _curRightStatus; | ||
bool _counting; | ||
|
||
double _lastHeartbeatTime; | ||
bool _listening; | ||
public: | ||
static CheesyVisionServer *GetInstance(); | ||
bool HasClientConnection(); | ||
void SetPort(int port){_listenPort = port;} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why should the user be allowed to change this? |
||
virtual void Run(); | ||
void StartListening(){_listening = true; Start();} | ||
void StopListening(){_listening = false; Pause();} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The implementation for these should be in the .cpp file. The more I look at this, the more I'm going to suggest dropping JankyTask and implementing the logic here. The logic really isn't hard, and the extra layer of abstraction doesn't really fit very well in this application. You want to start a thread on StartListening (locking it out so you can't call it more than once) and signal the thread to stop in StopListening (and lock it out there as well so it can't be stopped multiple times. Pretty simple. |
||
|
||
void Reset(); | ||
void UpdateCounts(bool left, bool right); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. UpdateCounts should be private |
||
void StartSamplingCounts(){_counting = true;} | ||
void StopSamplingCounts(){_counting = false;} | ||
|
||
bool GetLeftStatus(){return _curLeftStatus;} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You have some data corruption bugs here. The reader and writer for this data are in separate threads. It is not a good idea to rely on reads being atomic. Make a structure with all the data in it, and protect that with a lock. Grab the lock, make a tmp structure, release the lock, and return the structure. Much safer. |
||
bool GetRightStatus(){return _curRightStatus;} | ||
int GetLeftCount(){return _leftCount;} | ||
int GetRightCount(){return _rightCount;} | ||
int GetTotalCount(){return _totalCount;} | ||
|
||
|
||
}; | ||
|
||
|
||
#endif //CHEESYVISIONSERVER_H_ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
#include "WPILib.h" | ||
#include "jankyTask.h" | ||
#include <string> | ||
|
||
JankyTask::JankyTask(const char* taskName, UINT32 priority) { | ||
std::string name = taskName; | ||
char tmp[30]; | ||
|
||
if (!taskName) | ||
{ | ||
sprintf(tmp, "%d", GetFPGATime()); | ||
name = "jankyTask-"; | ||
name += tmp; | ||
} | ||
|
||
enabled_ = false; | ||
running_ = true; | ||
isDead_ = false; | ||
|
||
task_ = new Task(name.c_str(), (FUNCPTR)JankyTask::JankyPrivateStarterTask, priority); | ||
task_->Start((UINT32)this); | ||
} | ||
|
||
JankyTask::~JankyTask(){ | ||
task_->Stop(); | ||
|
||
delete task_; // Now kill the WPI class for the task. | ||
} | ||
|
||
void JankyTask::JankyPrivateStarterTask(JankyTask* task) { | ||
while (task->running_) { | ||
if (task->enabled_) { | ||
task->Run(); | ||
Wait(0.002); // Only wait 2ms when task is active. | ||
} | ||
else | ||
Wait(0.05); // 50 ms wait period while task is 'paused' | ||
} | ||
|
||
task->isDead_ = true; // Falling off the edge of the earth... | ||
} | ||
|
||
void JankyTask::Start() { | ||
enabled_ = true; | ||
} | ||
|
||
void JankyTask::Pause() { | ||
enabled_ = false; | ||
} | ||
|
||
void JankyTask::Terminate() { | ||
running_ = false; | ||
|
||
// Above told the task to exit on the next loop around. | ||
// That could take 2ms or 50ms based on whether it's in pause or run and how long | ||
// the actual Run() routine takes too. So we have to wait until we're really terminated here. | ||
while (!isDead_) { | ||
Wait(0.02); // Wait until we're really dead on that task. | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Class level comment saying what the goal of this is.