001 /*----------------------------------------------------------------------------*/ 002 /* Copyright (c) FIRST 2008-2012. All Rights Reserved. */ 003 /* Open Source Software - may be modified and shared by FRC teams. The code */ 004 /* must be accompanied by the FIRST BSD license file in the root directory of */ 005 /* the project. */ 006 /*----------------------------------------------------------------------------*/ 007 package edu.wpi.first.wpilibj.communication; 008 009 import com.sun.cldc.jna.Function; 010 import com.sun.cldc.jna.BlockingFunction; 011 import com.sun.cldc.jna.Pointer; 012 import com.sun.cldc.jna.NativeLibrary; 013 import com.sun.cldc.jna.Structure; 014 import com.sun.cldc.jna.TaskExecutor; 015 016 /** 017 * Contains the code necessary to communicate between the robot and the driver station. 018 */ 019 public final class FRCControl { 020 021 private static final TaskExecutor taskExecutor = new TaskExecutor("FRCControl Task executor"); 022 023 // int getCommonControlData(FRCCommonControlData *data, int wait_ms); 024 private static final BlockingFunction getCommonControlDataFn = NativeLibrary.getDefaultInstance().getBlockingFunction("getCommonControlData"); 025 026 // int getDynamicControlData(UINT8 type, char *dynamicData, INT32 maxLength, int wait_ms); 027 private static final BlockingFunction getDynamicControlDataFn = NativeLibrary.getDefaultInstance().getBlockingFunction("getDynamicControlData"); 028 029 // int setStatusDataFloatAsInt(int battery, UINT8 dsDigitalOut, UINT8 updateNumber, 030 // const char *userDataHigh, int userDataHighLength, 031 // const char *userDataLow, int userDataLowLength, int wait_ms); 032 private static final BlockingFunction setStatusDataFn = NativeLibrary.getDefaultInstance().getBlockingFunction("setStatusDataFloatAsInt"); 033 034 // int setErrorData(const char *errors, int errorsLength, int wait_ms); 035 private static final BlockingFunction setErrorDataFn = NativeLibrary.getDefaultInstance().getBlockingFunction("setErrorData"); 036 037 // int setUserDsLcdData(const char *userDsLcdData, int userDsLcdDataLength, int wait_ms); 038 private static final BlockingFunction setUserDsLcdDataFn = NativeLibrary.getDefaultInstance().getBlockingFunction("setUserDsLcdData"); 039 040 // int overrideIOConfig(const char *ioConfig, int wait_ms); 041 private static final BlockingFunction overrideIOConfigFn = NativeLibrary.getDefaultInstance().getBlockingFunction("overrideIOConfig"); 042 043 // void setNewDataSem(SEM_ID); 044 private static final BlockingFunction setNewDataSemFn = NativeLibrary.getDefaultInstance().getBlockingFunction("setNewDataSem"); 045 046 // void FRC_NetworkCommunication_observeUserProgramStarting(void); 047 private static final Function observeUserProgramStartingFn = NativeLibrary.getDefaultInstance().getFunction("FRC_NetworkCommunication_observeUserProgramStarting"); 048 049 // void FRC_NetworkCommunication_observeUserProgramDisabled(void); 050 private static final Function observeUserProgramDisabledFn = NativeLibrary.getDefaultInstance().getFunction("FRC_NetworkCommunication_observeUserProgramDisabled"); 051 052 // void FRC_NetworkCommunication_observeUserProgramAutonomous(void); 053 private static final Function observeUserProgramAutonomousFn = NativeLibrary.getDefaultInstance().getFunction("FRC_NetworkCommunication_observeUserProgramAutonomous"); 054 055 // void FRC_NetworkCommunication_observeUserProgramTeleop(void); 056 private static final Function observeUserProgramTeleopFn = NativeLibrary.getDefaultInstance().getFunction("FRC_NetworkCommunication_observeUserProgramTeleop"); 057 058 // void FRC_NetworkCommunication_observeUserProgramTeleop(void); 059 private static final Function observeUserProgramTestFn = NativeLibrary.getDefaultInstance().getFunction("FRC_NetworkCommunication_observeUserProgramTest"); 060 061 062 static { 063 getCommonControlDataFn.setTaskExecutor(taskExecutor); 064 getDynamicControlDataFn.setTaskExecutor(taskExecutor); 065 setStatusDataFn.setTaskExecutor(taskExecutor); 066 setErrorDataFn.setTaskExecutor(taskExecutor); 067 setUserDsLcdDataFn.setTaskExecutor(taskExecutor); 068 setNewDataSemFn.setTaskExecutor(taskExecutor); 069 overrideIOConfigFn.setTaskExecutor(taskExecutor); 070 } 071 072 /** 073 * The size of the IO configuration data 074 */ 075 public static final int IO_CONFIG_DATA_SIZE = 32; 076 /** 077 * The size of the user control data 078 */ 079 public static final int USER_CONTROL_DATA_SIZE = 936 - IO_CONFIG_DATA_SIZE; 080 /** 081 * The size of the user status data 082 */ 083 public static final int USER_STATUS_DATA_SIZE = 984; 084 /** 085 * The size of the user driver station display data 086 */ 087 public static final int USER_DS_LCD_DATA_SIZE = 128; 088 089 private FRCControl() { 090 } 091 092 /** 093 * A simple 1-element cache that keeps a pointer to native memory around. 094 * Works best if repeatedly asked for buffers of same size. 095 * 096 * WARNING: It's expected that the users of this cache are synchronized 097 * 098 * @TODO free the cache at shutdown... 099 */ 100 public static class CachedNativeBuffer { 101 102 private Pointer buffer; 103 104 public Pointer getBufferSized(int size) { 105 if (buffer == null) { 106 buffer = new Pointer(size); 107 } 108 if (size > buffer.getSize()) { 109 buffer.free(); 110 buffer = new Pointer(size); 111 } 112 return buffer; 113 } 114 115 public void free() { 116 if (buffer != null) { 117 buffer.free(); 118 buffer = null; 119 } 120 } 121 } /* CachedNativeBuffer */ 122 123 124 public static abstract class DynamicControlData extends Structure { 125 } 126 127 private static final CachedNativeBuffer controlDataCache = new CachedNativeBuffer(); 128 private static final CachedNativeBuffer statusDataCacheHigh = new CachedNativeBuffer(); 129 private static final CachedNativeBuffer statusDataCacheLow = new CachedNativeBuffer(); 130 private static final CachedNativeBuffer ioConfigDataCache = new CachedNativeBuffer(); 131 132 /** 133 * Get the control data from the driver station. The parameter "data" 134 * is only updated when the method returns 0. 135 * 136 * @param data the object to store the results in (out param) 137 * @param wait_ms the maximum time to wait 138 * @return 0 if new data, 1 if no new data, 2 if access timed out. 139 */ 140 public static int getCommonControlData(FRCCommonControlData data, int wait_ms) { 141 int res = getCommonControlDataFn.call2(data.getPointer(), wait_ms); 142 if (res == 0) { 143 // Copy the FRCControlData from C-accessible memory 144 data.read(); 145 } 146 147 return res; 148 } 149 150 /** 151 * Get the dynamic control data from the driver station. The parameter 152 * "dynamicData" is only updated when the method returns 0. 153 * @param type The type to get. 154 * @param dynamicData The array to hold the result in. 155 * @param maxLength The maximum length of the data. 156 * @param wait_ms The maximum time to wait. 157 * @return 0 if new data, 1 if no new data, 2 if access timed out. 158 */ 159 public static int getDynamicControlData(byte type, DynamicControlData dynamicData, int maxLength, int wait_ms) { 160 synchronized (controlDataCache) { 161 dynamicData.write(); 162 int res = getDynamicControlDataFn.call4(type, dynamicData.getPointer(), maxLength, wait_ms); 163 if (res == 0) 164 dynamicData.read(); 165 return res; 166 } 167 } 168 169 /** 170 * Right new io config data. 171 * @param ioConfig The data to write / read 172 * @param wait_ms The maximum time to wait. 173 * @return 0 if new data, 1 if no new data, 2 if access timed out. 174 */ 175 public static int overrideIOConfig(DynamicControlData ioConfig, int wait_ms) { 176 synchronized (ioConfigDataCache) { 177 ioConfig.write(); 178 int res = overrideIOConfigFn.call2(ioConfig.getPointer(), wait_ms); 179 if (res == 0) 180 ioConfig.read(); 181 return res; 182 } 183 } 184 185 /** 186 * Set the status data to send to the ds 187 * 188 * @param battery the battery voltage 189 * @param dsDigitalOut value to set the digital outputs on the ds to 190 * @param updateNumber unique ID for this update (incrementing) 191 * @param userDataHigh additional high-priority user data bytes 192 * @param userDataHighLength number of high-priority data bytes 193 * @param userDataLow additional low-priority user data bytes 194 * @param userDataLowLength number of low-priority data bytes 195 * @param wait_ms the timeout 196 * @return 0 on success, 1 if userData.length is too big, 2 if semaphore could not be taken in wait_ms. 197 */ 198 public static int setStatusData(double battery, int dsDigitalOut, 199 int updateNumber, byte[] userDataHigh, int userDataHighLength, 200 byte[] userDataLow, int userDataLowLength, int wait_ms) { 201 synchronized (statusDataCacheHigh) { 202 //System.out.println("udl " + userData.length); 203 // Copy the userdata byte[] to C-accessible memory 204 Pointer userDataPtrHigh = statusDataCacheHigh.getBufferSized(userDataHighLength); // new Pointer(userData.length); 205 userDataPtrHigh.setBytes(0, userDataHigh, 0, userDataHighLength); 206 Pointer userDataPtrLow = statusDataCacheLow.getBufferSized(userDataLowLength); // new Pointer(userData.length); 207 userDataPtrLow.setBytes(0, userDataLow, 0, userDataLowLength); 208 209 //System.out.print("Writing "); 210 //System.out.print(userData.length); 211 //System.out.println(" bytes of status data to network."); 212 213 int res = setStatusDataFn.call8(Float.floatToIntBits((float) battery), 214 dsDigitalOut, updateNumber, 215 userDataPtrHigh.address().toUWord().toPrimitive(), userDataHighLength, 216 userDataPtrLow.address().toUWord().toPrimitive(), userDataLowLength, 217 wait_ms); 218 219 //System.out.println("Data transfered."); 220 return res; 221 } 222 } 223 224 /** 225 * Send data to the driver station's error panel 226 * @param bytes the byte array containing the properly formatted information for the display 227 * @param length the length of the byte array 228 * @param timeOut the maximum time to wait 229 */ 230 public static void setErrorData(byte[] bytes, int length, int timeOut) { 231 Pointer textPtr = new Pointer(bytes.length); 232 textPtr.setBytes(0, bytes, 0, bytes.length); 233 setErrorDataFn.call3(textPtr, length, timeOut); 234 textPtr.free(); 235 } 236 237 /** 238 * Send data to the driver station's error panel 239 * @param textPtr pointer to C byte array containing the properly formatted information for the display 240 * @param length the length of the byte array 241 * @param timeOut the maximum time to wait 242 */ 243 public static void setErrorData(Pointer textPtr, int length, int timeOut) { 244 if (length > textPtr.getSize()) { 245 throw new IllegalArgumentException(); 246 } 247 setErrorDataFn.call3(textPtr, length, timeOut); 248 } 249 250 /** 251 * Send data to the driver station's user panel 252 * @param bytes the byte array containing the properly formatted information for the display 253 * @param length the length of the byte array 254 * @param timeOut the maximum time to wait 255 */ 256 public static void setUserDsLcdData(byte[] bytes, int length, int timeOut) { 257 Pointer textPtr = new Pointer(bytes.length); 258 textPtr.setBytes(0, bytes, 0, bytes.length); 259 setUserDsLcdDataFn.call3(textPtr, length, timeOut); 260 textPtr.free(); 261 } 262 263 /** 264 * Set the semaphore for the communications task to use 265 * @param sem the semaphore to use 266 */ 267 public static void setNewDataSem(Semaphore sem) { 268 if (sem == null || sem.m_semaphore == null) { 269 throw new NullPointerException("Null provided for a semaphore"); 270 } 271 setNewDataSemFn.call1(sem.m_semaphore); 272 } 273 274 /** 275 * Let the DS know that the user is loading a new app. 276 */ 277 public static void observeUserProgramStarting() { 278 observeUserProgramStartingFn.call0(); 279 } 280 281 public static void observeUserProgramDisabled() { 282 observeUserProgramDisabledFn.call0(); 283 } 284 285 public static void observeUserProgramAutonomous() { 286 observeUserProgramAutonomousFn.call0(); 287 } 288 289 public static void observeUserProgramTeleop() { 290 observeUserProgramTeleopFn.call0(); 291 } 292 293 public static void observeUserProgramTest() { 294 observeUserProgramTestFn.call0(); 295 } 296 }