BowlerKernel
DyIOChannel.java
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright 2010 Neuron Robotics, LLC
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  ******************************************************************************/
15 package com.neuronrobotics.sdk.dyio;
16 
17 import java.util.ArrayList;
18 import java.util.Collection;
19 
20 import com.neuronrobotics.sdk.commands.bcs.io.AsyncThreshholdEdgeType;
21 import com.neuronrobotics.sdk.commands.bcs.io.GetChannelModeCommand;
22 import com.neuronrobotics.sdk.commands.bcs.io.GetValueCommand;
23 import com.neuronrobotics.sdk.commands.bcs.io.SetChannelValueCommand;
24 import com.neuronrobotics.sdk.commands.bcs.io.setmode.SetChannelModeCommand;
25 import com.neuronrobotics.sdk.common.BowlerAbstractCommand;
26 import com.neuronrobotics.sdk.common.BowlerDatagram;
27 import com.neuronrobotics.sdk.common.BowlerMethod;
28 import com.neuronrobotics.sdk.common.ByteList;
29 import com.neuronrobotics.sdk.common.InvalidResponseException;
30 import com.neuronrobotics.sdk.common.Log;
31 import com.neuronrobotics.sdk.dyio.peripherals.DyIOAbstractPeripheral;
32 import com.neuronrobotics.sdk.util.ThreadUtil;
33 // TODO: Auto-generated Javadoc
39 public class DyIOChannel implements IDyIOChannel {
40 
42  private int MAXATTEMPTS = 3;
43 
45  private float cachedTime=0;
46 
48  private DyIO device;
49 
51  private int number;
52 
54  private boolean editable;
55 
57  private DyIOChannelMode current=null;
58 
60  private boolean isAsync=true;
61 
63  private ArrayList<IChannelEventListener> listeners = new ArrayList<IChannelEventListener>();
64 
66  private ArrayList< IDyIOChannelModeChangeListener> modeListeners = new ArrayList< IDyIOChannelModeChangeListener>();
67 
69  protected int cachedValue = 0;
70 
72  private boolean cachedMode=false;
73 
76 
78  private int previousValue = 1;
79 
81  private boolean haveSetMode = false;
82 
84  private boolean settingMode=false;
92  public DyIOChannel(DyIO dyio, int channel, DyIOChannelMode mode, boolean isEditable) {
93  update(dyio, channel, mode, isEditable);
94  }
95 
104  public void update(DyIO dyio, int channel, DyIOChannelMode mode, boolean isEditable) {
105  setDevice(dyio);
106  number = channel;
108  if(getCurrentMode() == null){
109  setMode(mode);
110  }else{
111  setMode(mode,isAsync);
112  }
113  fireModeChangeEvent(mode);
115  Log.error("Failed to update channel: "+ channel);
116  throw new RuntimeException("Failed to update channel: "+ channel);
117  }
118  }
119 
120 
125  public int getChannelNumber() {
126  return number;
127  }
128 
134  public boolean isEditable() {
135  return editable;
136  }
137 
142  public void send(BowlerAbstractCommand command) {
143  getDevice().send(command);
144  }
145 
146 
151  modeListeners.clear();
152  }
153 
161  if(!modeListeners.contains(l)) {
162  return;
163  }
164 
165  modeListeners.remove(l);
166  }
167 
175  if(modeListeners.contains(l)) {
176  return;
177  }
178  modeListeners.add(l);
179  }
180 
185  listeners.clear();
186  }
187 
195  if(!listeners.contains(l)) {
196  return;
197  }
198 
199  listeners.remove(l);
200  }
201 
209  if(listeners.contains(l)) {
210  return;
211  }
212 
213  listeners.add(l);
214  }
215 
223  public boolean setMode(DyIOChannelMode mode) {
224  return setMode(mode, isDefaultAsync(mode));
225  }
226 
238  public DyIOChannelMode getMode(boolean resync) {
239  resync(false);
240  return getMode();
241  }
242 
243 
249  public DyIO getDevice() {
250  return device;
251  }
252 
258  public void resync(boolean all) {
259 
260  if(all) {
261  getDevice().resync();
262  return;
263  }
265  //System.out.println(bd);
267  throw new RuntimeException();
268  }
269 
275  public boolean canBeMode(DyIOChannelMode m) {
276  Collection<DyIOChannelMode> modes = getAvailableModes();
277  for(DyIOChannelMode mo:modes) {
278  if(mo == m)
279  return true;
280  }
281  return false;
282  }
287  public boolean hasAsync(){
288  if(getMode() == null)
289  return false;
290  switch(getMode()){
291  case ANALOG_IN:
292  case COUNT_IN_INT:
293  case COUNT_OUT_INT:
294  case DIGITAL_IN:
295  return true;
296  default:
297  return false;
298  }
299  }
303  private ArrayList<DyIOChannelMode> myModes;
304 
310  public Collection<DyIOChannelMode> getAvailableModes() {
311  if(myModes== null)
313 
314  for(int i=0;i<myModes.size();i++){
315  if(myModes.get(i) == DyIOChannelMode.SERVO_OUT){
316  myModes.remove(i);
317  }
318  }
319 
320  if(getDevice().isServoPowerSafeMode()){
321  if(number < (getDevice().getDyIOChannelCount()/2) && device.getBankAState() != DyIOPowerState.REGULATED) {
323  }
324 
325  if(number >= (getDevice().getDyIOChannelCount()/2) && device.getBankBState() != DyIOPowerState.REGULATED) {
327  }
328  }else{
330  }
331 
332  return myModes;
333  }
334 
342  if(isStreamChannel())
343  return 0;
344  return e.getValue();
345  }
346 
352  protected void fireChannelEvent(DyIOChannelEvent e) {
353  int value= parseDyIOChannelEvent(e);
354  if((getPreviousValue() == value) && !isStreamChannel() ){
355  //
356  return;
357  }else{
358  Log.info("Value is not the same, last was: "+getPreviousValue()+" current: "+value);
359  }
360  setPreviousValue(value);
361  for(int i=0;i<listeners.size();i++) {
362  listeners.get(i).onChannelEvent(e);
363  }
364  }
365 
372  boolean ok = false;
373  String modeList=" ";
375  if(md == e)
376  ok=true;
377  modeList +=" "+md.toString()+",";
378  }
379  if(! ok){
380  Log.error(e+" Mode is invalid for: "+number+modeList);
382  }
383 
384  try {
385  if(!canBeMode(e)) {
386  String message = this.getClass()+" Can not set channel: "+getChannelNumber()+" to mode: "+e;
387  Log.error(message);
388  //throw new RuntimeException(message);
389  }
390  }catch(RuntimeException ex) {
391  ex.printStackTrace();
392  throw ex;
393  }
394  if(e==getMode()) {
395  Log.info("Mode not changed: "+getChannelNumber()+" mode: "+getMode()+" not notifying");
396  //return;
397  }
398  this.current = e;
399  for(int i=0;i<modeListeners.size();i++) {
400  //Log.debug("Notifying: "+modeListeners.get(i).getClass());
401  modeListeners.get(i).onModeChange(e);
402  }
403  }
404  /* (non-Javadoc)
405  * @see java.lang.Object#toString()
406  */
407 
408  public String toString() {
409  return String.format("(%02d) - %-20s", getChannelNumber(), getMode());
410  }
411 
412  /* (non-Javadoc)
413  * @see com.neuronrobotics.sdk.dyio.IDyIOChannel#getChannel()
414  */
415 
417  return this;
418  }
419 
420  /* (non-Javadoc)
421  * @see com.neuronrobotics.sdk.dyio.IDyIOChannel#getMode()
422  */
423 
425  return getCurrentMode();
426  }
427 
428  /* (non-Javadoc)
429  * @see com.neuronrobotics.sdk.dyio.IDyIOChannel#getValue()
430  */
431 
432  public int getValue() {
433 
434  int val=0;
435  if(getDevice().isLegacyParser()){
436  BowlerDatagram response=null;
437  try {
438  response = getDevice().send(new GetValueCommand(number));
439  } catch (InvalidResponseException e) {
440  response = getDevice().send(new GetValueCommand(number));
441  }
442  ByteList bl = response.getData();
443 
444  Byte b = bl.pop();
445  if(b==null || b.intValue()!=number){
446  Log.error("Failed to get value "+response);
447  return 0;
448  }
449 
450  val = new DyIOChannelEvent(this,bl).getValue();
451  setCachedValue(val);
452  setPreviousValue(val);
453  }else{
454 
455 // Object [] args =getDevice().send("bcs.io.*;0.3;;",
456 // BowlerMethod.GET,
457 // "gchv",
458 // new Object[]{number});
459 // val=(Integer)args[1];
460 // Log.debug("Got Value: "+val);
461 
462  // For the new API the channel values should come in through the asynchronous path.
463  val = getPreviousValue();
464  }
465 
466  return val;
467  }
468 
469  /* (non-Javadoc)
470  * @see com.neuronrobotics.sdk.dyio.IDyIOChannel#setMode(com.neuronrobotics.sdk.dyio.DyIOChannelMode, boolean)
471  */
472 
473  public boolean setMode(DyIOChannelMode mode, boolean async) {
474  if(settingMode)
475  return true;
476 
477  //resyncIfNotSynced();
478  if(mode == null) {
479  throw new RuntimeException("Mode can not be set to null, must be set to a mode");
480  }
481  if(getMode() == null) {
482  Log.info(this.getClass()+" First time setting mode.");
483  fireModeChangeEvent(mode);
484  isAsync = isDefaultAsync(mode);
485  haveSetMode=false;
486  }else if ((getMode() == mode) && (async == isAsync) ) {
487  Log.debug(this.getClass()+"Channel: "+getChannelNumber()+" is already "+getMode());
488  return true;
489  }
490 
491  if(!canBeMode(mode)){
492  if(mode == DyIOChannelMode.SERVO_OUT)
493  new RuntimeException("\nChannel: "+getChannelNumber()+" can not be mode '"+mode+"' in current configuration. \nCheck the power switch settings and availible modes.").printStackTrace();
494  else
495  new RuntimeException("\nChannel: "+getChannelNumber()+" can not be mode '"+mode+"'.").printStackTrace();
496  mode=getMode();
497  }
498  settingMode=true;
499 
500  for(int i = 0; i < MAXATTEMPTS; i++) {
501  try {
502  isAsync = async;
503  haveSetMode=true;
507  if(getDevice().isLegacyParser()){
508  getDevice().send(new SetChannelModeCommand(number, mode, async));
509 
510  if(!getDevice().isMuteResyncOnModeChange()){
511  try {
512  getDevice().resync();
513  }catch(RuntimeException e) {
514  e.printStackTrace();
516  }
517  }else{
518  Log.info("Not resyncing from channel: "+getChannelNumber());
519  fireModeChangeEvent(mode);
520  }
521  }else{
522  //int printlevel = Log.getMinimumPrintLevel();
523  //Log.enableInfoPrint();
524  Object [] args = getDevice().send("bcs.io.setmode.*;0.3;;",
526  "schm",
527  new Object[]{getChannelNumber(),mode.getValue(),async?1:0});
528  ByteList currentModes = (ByteList) args[0];
529  //System.out.println("Setting # "+getChannelNumber()+" to "+mode);
530  for (int j=0;j<getDevice().getChannels().size();j++){
531  DyIOChannelMode cm = DyIOChannelMode.get(currentModes.getByte(j));
532  if(getDevice().getChannel(j).getCurrentMode()!=cm ){
533  //System.err.println("Setting # "+j+" to "+cm);
535  }
536  }
537  //Log.setMinimumPrintLevel(printlevel);
538  }
539  settingMode=false;
540  // Defaultuing the advanced async to on
541  if(isAsync)
543  return true;
544  } catch (InvalidResponseException e) {
545  Log.error(e.getMessage());
546  try {
547  Thread.sleep(100);
548  } catch (InterruptedException e1) {
549  settingMode=false;
550  return false;
551  }
552  }
553  }
554  settingMode=false;
555  return false;
556  }
557 
558 
559  /* (non-Javadoc)
560  * @see com.neuronrobotics.sdk.dyio.IDyIOChannel#setValue(int)
561  */
562 
563  public boolean setValue(int value) {
564 
565  setCachedValue(value);
566  setCachedTime(0);
567  if(cachedMode)
568  return true;
569  if(dap!=null)
570  return dap.flush();
571  return flush();
572  }
578  public boolean flush() {
579 // if(getCachedMode())
580 // throw new RuntimeException("In chached mode and flushing from channel");
581  //Log.enableDebugPrint(true);
582  Log.info("Flushing channel: "+number);
583  if(getDevice().isLegacyParser()){
584  ByteList b = new ByteList();
585  switch(getMode()){
586  case COUNT_IN_INT:
587  case COUNT_IN_DIR:
588  case COUNT_IN_HOME:
589  case COUNT_OUT_INT:
590  case COUNT_OUT_DIR:
591  case COUNT_OUT_HOME:
592  b.addAs32(getCachedValue());
593  b.addAs32((int)(getCachedTime()*1000));
594  break;
595  case SERVO_OUT:
596  b.add(getCachedValue());
597  b.addAs16((int)(getCachedTime()*1000));
598  break;
599  default:
600  b.add(getCachedValue());
601  }
602  Log.info("Setting channel: "+getChannelNumber()+" to value: "+b);
603  boolean back = setValue(b);
604  //Log.enableDebugPrint(false);
605  return back;
606  }else{
607  //Log.info("Setting channel: "+number+" to value: "+getCachedValue());
608  getDevice().send( "bcs.io.*;0.3;;",
610  "schv",
611  new Object[]{number,getCachedValue(),(int)(getCachedTime()*1000)});
612  return true;
613  }
614  }
615 
616 
617 
618 
624  public void setCachedValue(int cachedValue) {
625  this.cachedValue = cachedValue;
626  }
627 
633  public int getCachedValue() {
634  return cachedValue;
635  }
640  public boolean getCachedMode() {
641  return cachedMode;
642  }
643 
649  public void setCachedMode(boolean mode) {
650  cachedMode=mode;
651  }
652 
659  this.dap = dap;
660  }
661 
668  return dap;
669  }
670 
671 
677  public boolean configAdvancedAsyncNotEqual(){
678  return configAdvancedAsyncNotEqual(100);
679  }
680 
688  public boolean configAdvancedAsyncDeadBand(int deadbandSize){
689  return configAdvancedAsyncDeadBand(100,deadbandSize);
690  }
691 
700  public boolean configAdvancedAsyncTreshhold(int threshholdValue, AsyncThreshholdEdgeType edgeType){
701  return configAdvancedAsyncTreshhold(100, threshholdValue, edgeType);
702  }
703 
712  return configAdvancedAsyncAutoSample(100);
713  }
714 
720  public boolean configAdvancedAsyncNotEqual(int msTime){
721  isAsync=true;
723  }
724 
732  public boolean configAdvancedAsyncDeadBand(int msTime,int deadbandSize){
733  isAsync=true;
734  return getDevice().configAdvancedAsyncDeadBand(getChannelNumber(),msTime,deadbandSize);
735  }
736 
745  public boolean configAdvancedAsyncTreshhold(int msTime,int threshholdValue, AsyncThreshholdEdgeType edgeType){
746  isAsync=true;
747  return getDevice().configAdvancedAsyncTreshhold(getChannelNumber(),msTime, threshholdValue, edgeType);
748  }
749 
757  public boolean configAdvancedAsyncAutoSample(int msTime){
758  isAsync=true;
760  }
761 
762 // /**
763 // * Sets the current internal mode variable.
764 // * @param mode the mode to set to.
765 // */
766 // private void setCurrentMode(DyIOChannelMode mode) {
767 //
768 // }
774  return current;
775  }
776 
783  public void setCachedTime(float cachedTime) {
784  this.cachedTime = cachedTime;
785  }
786 
792  public float getCachedTime() {
793  return cachedTime;
794  }
795 
801  public void setAsync(boolean b) {
802  setMode(getMode(), b);
803  }
804 
810  /*
811  * Helpers
812  */
813  private void setPreviousValue(int previousValue) {
814  this.previousValue = previousValue;
815  }
816 
822  protected int getPreviousValue() {
823  return previousValue;
824  }
825 
831  public boolean isStreamChannel(){
832  switch(getMode()){
833  case USART_RX:
834  case USART_TX:
835  case SPI_CLOCK:
836  case SPI_MISO:
837  case SPI_MOSI:
838  case PPM_IN:
839  return true;
840  default:
841  return false;
842  }
843  }
844 
850  private void setDevice(DyIO device) {
851  this.device = device;
852  }
853 
860  private boolean isDefaultAsync(DyIOChannelMode m) {
861  return true;
862  }
863 
865  private boolean synced = false;
866 
870  private void resyncIfNotSynced() {
871  if(synced==false) {
872  synced = true;
873  resync(false);
874  }
875  }
876 
883  public boolean isStreamtMode( DyIOChannelMode m) {
884  switch(m) {
885  case USART_RX:
886  case PPM_IN:
887  case SPI_CLOCK:
888  case SPI_MISO:
889  case SPI_MOSI:
890  case USART_TX:
891  return true;
892  case SERVO_OUT:
893  case ANALOG_OUT:
894  case DC_MOTOR_DIR:
895  case DC_MOTOR_VEL:
896  case PWM_OUT:
897  case SPI_SELECT:
898  case DIGITAL_OUT:
899  case COUNT_OUT_DIR:
900  case COUNT_OUT_HOME:
901  case COUNT_OUT_INT:
902  case ANALOG_IN:
903  case COUNT_IN_DIR:
904  case COUNT_IN_HOME:
905  case COUNT_IN_INT:
906  case DIGITAL_IN:
907  case NO_CHANGE:
908  case OFF:
909  return false;
910  }
911  return false;
912  }
913 
920  private boolean isOutputMode( DyIOChannelMode m) {
921  switch(m) {
922  case SERVO_OUT:
923  case ANALOG_OUT:
924  case DC_MOTOR_DIR:
925  case DC_MOTOR_VEL:
926  case PWM_OUT:
927  case SPI_CLOCK:
928  case SPI_MISO:
929  case SPI_MOSI:
930  case SPI_SELECT:
931  case USART_TX:
932  case DIGITAL_OUT:
933  case COUNT_OUT_DIR:
934  case COUNT_OUT_HOME:
935  case COUNT_OUT_INT:
936  return true;
937  case ANALOG_IN:
938  case COUNT_IN_DIR:
939  case COUNT_IN_HOME:
940  case COUNT_IN_INT:
941  case DIGITAL_IN:
942  case NO_CHANGE:
943  case OFF:
944  case PPM_IN:
945  case USART_RX:
946  return false;
947  }
948  return false;
949  }
950 
951  /* (non-Javadoc)
952  * @see com.neuronrobotics.sdk.dyio.IDyIOChannel#setValue(com.neuronrobotics.sdk.common.ISendable)
953  */
954 
955  public boolean setValue(ByteList data) {
956 
957  if(getDevice().isLegacyParser()){
958  int attempts = MAXATTEMPTS;
960  attempts=1;
961  for(int i = 0; i < attempts; i++) {
962  try {
964  return true;
965  } catch (InvalidResponseException e) {
966  try {
967  Thread.sleep(100);
968  } catch (InterruptedException e1) {
969  return false;
970  }
971  }
972  }
973  }else{
974  if(!isStreamChannel())
975  throw new RuntimeException("Only stream channels should talk to this method");
976  getDevice().send("bcs.io.*;0.3;;",
978  "strm",
979  new Object[]{number,data});
980  }
981 
982  return false;
983  }
984 }
synchronized boolean add(byte data)
Definition: ByteList.java:149
static void info(String message)
Definition: Log.java:110
static void error(String message)
Definition: Log.java:92
static void debug(String message)
Definition: Log.java:128
boolean setMode(DyIOChannelMode mode)
boolean isStreamtMode(DyIOChannelMode m)
ArrayList< DyIOChannelMode > myModes
boolean setMode(DyIOChannelMode mode, boolean async)
void fireModeChangeEvent(DyIOChannelMode e)
void fireChannelEvent(DyIOChannelEvent e)
DyIOChannelMode getMode(boolean resync)
boolean configAdvancedAsyncAutoSample(int msTime)
void setPreviousValue(int previousValue)
boolean isDefaultAsync(DyIOChannelMode m)
ArrayList< IChannelEventListener > listeners
boolean configAdvancedAsyncTreshhold(int msTime, int threshholdValue, AsyncThreshholdEdgeType edgeType)
boolean configAdvancedAsyncDeadBand(int deadbandSize)
boolean canBeMode(DyIOChannelMode m)
int parseDyIOChannelEvent(DyIOChannelEvent e)
void removeChannelEventListener(IChannelEventListener l)
void update(DyIO dyio, int channel, DyIOChannelMode mode, boolean isEditable)
void addChannelModeChangeListener(IDyIOChannelModeChangeListener l)
void removeChannelModeChangeListener(IDyIOChannelModeChangeListener l)
ArrayList< IDyIOChannelModeChangeListener > modeListeners
boolean configAdvancedAsyncNotEqual(int msTime)
void setDap(DyIOAbstractPeripheral dap)
boolean configAdvancedAsyncDeadBand(int msTime, int deadbandSize)
boolean isOutputMode(DyIOChannelMode m)
boolean configAdvancedAsyncTreshhold(int threshholdValue, AsyncThreshholdEdgeType edgeType)
DyIOChannel(DyIO dyio, int channel, DyIOChannelMode mode, boolean isEditable)
Collection< DyIOChannelMode > getAvailableModes()
void addChannelEventListener(IChannelEventListener l)
void send(BowlerAbstractCommand command)
boolean configAdvancedAsyncDeadBand(int pin, int deadbandSize)
Definition: DyIO.java:980
DyIOPowerState getBankBState()
Definition: DyIO.java:714
ArrayList< DyIOChannelMode > getAvailibleChannelModes(int channel)
Definition: DyIO.java:1370
void setMuteResyncOnModeChange(boolean muteResyncOnModeChange)
Definition: DyIO.java:1187
DyIOPowerState getBankAState()
Definition: DyIO.java:704
Object[] send(String NS, BowlerMethod method, String rpcString, Object[] arguments)
Definition: DyIO.java:168
ArrayList< DyIOChannel > getChannels()
Definition: DyIO.java:311
boolean configAdvancedAsyncAutoSample(int pin)
Definition: DyIO.java:1005
boolean configAdvancedAsyncTreshhold(int pin, int threshholdValue, AsyncThreshholdEdgeType edgeType)
Definition: DyIO.java:993
void resync(int channel)
Definition: DyIO.java:326
boolean configAdvancedAsyncNotEqual(int pin)
Definition: DyIO.java:968
DyIOChannel getChannel(int channel)
Definition: DyIO.java:160
static DyIOChannelMode get(byte code)