Compare commits

..

66 Commits

Author SHA1 Message Date
Yichin wong f5018b5c37 Update README.md 2019-08-29 16:43:37 +00:00
Yichin wong 2a17781fde Update README.md 2019-08-15 04:28:40 +00:00
Yichin wong 67d52bcd75 Update README.md 2019-08-15 04:25:11 +00:00
Ta-Shun Su b96505d79c fix README style 2019-07-25 18:15:39 +08:00
Ta-Shun Su 7083101d79 fix README style 2019-07-25 18:05:14 +08:00
Ta-Shun Su ee70b207ca update README 2019-07-25 18:03:11 +08:00
Ta-Shun Su 314bb70489 update README 2019-07-25 17:57:05 +08:00
Ta-Shun Su 459f4850ef update test 2019-07-25 14:16:28 +08:00
Ta-Shun Su dbc2e3a568 save 2019-07-25 11:56:09 +08:00
Ta-Shun Su 1f4cee9279 headstage_notify.h 2019-07-25 11:54:16 +08:00
Ta-Shun Su f18f05cd1d headstage.h for uni 2019-07-25 11:46:33 +08:00
Ta-Shun Su 93816a8d36 led.h for GPIO, fix from neulive1.2 2019-07-25 11:30:11 +08:00
Ta-Shun Su 18a8fde7de Merge branch 'neulive1.2/master' 2019-07-25 11:17:37 +08:00
yichin 7742ab0c9c fix scan data error 2019-06-25 18:21:04 +08:00
Ta-Shun Su 1d1e08771d add old sti instruction generator 2019-06-13 14:44:11 +08:00
Ta-Shun Su 916e27ba33 save 2019-06-06 15:50:05 +08:00
Ta-Shun Su 598c3e2629 improve python test code with VIS 2019-06-06 14:47:57 +08:00
Ta-Shun Su ca39a15e60 add test 2019-06-05 19:08:24 +08:00
yichin 2c992d8526 compile pass for sti 2019-06-05 17:28:53 +08:00
Ta-Shun Su 127742b194 save 2019-06-05 17:19:57 +08:00
Ta-Shun Su dff979cbe6 Merge branch 'neuliveSTI/1210' 2019-06-05 17:17:41 +08:00
Ta-Shun Su 3b13a0ff90 reformat 2019-06-05 17:14:18 +08:00
yichin 1e061f2511 sti adc for vsen 2019-06-05 16:14:42 +08:00
yichin cc2648585c add adc pin define from LP 2019-06-05 16:07:25 +08:00
Ta-Shun Su b965f81fc4 notify format 2019-06-03 17:03:01 +08:00
Ta-Shun Su b5ddf300b9 reformat 2019-06-03 16:45:37 +08:00
Ta-Shun Su 22175f379f Merge branch 'neuliveSTI/1210' 2019-06-03 16:32:19 +08:00
yichin 6ff966df58 sti comment debug code 2019-06-03 16:29:49 +08:00
yichin 65f159fad2 fix disconnect event 2019-06-03 16:29:24 +08:00
yichin 515fc57307 sti adc 2019-06-03 16:22:17 +08:00
yichin b84fbb6044 sti clock 2019-06-03 15:51:08 +08:00
Ta-Shun Su d1cdaf7041 reformat 2019-06-03 15:37:09 +08:00
yichin d824b1fbd9 save 2019-06-03 15:31:07 +08:00
yichin 0df352d6ff sti clock 2019-06-03 12:48:23 +08:00
yichin c27b6a0ac7 sti notify format 2019-06-03 12:36:28 +08:00
yichin e1152f6713 bug fix 2019-06-03 12:03:25 +08:00
yichin e6ab11b004 sti use one callback to control two channel which has same parameter 2019-06-03 11:06:22 +08:00
yichin e3e40d25e9 save 2019-05-28 19:18:57 +08:00
yichin 495d4deb91 save 2019-05-28 18:53:55 +08:00
yichin aa662f4a7b save 2019-05-27 19:59:06 +08:00
yichin 21f17ab7a3 tow channel test 2019-05-27 18:26:25 +08:00
yichin 6000816833 save 2019-05-27 18:17:43 +08:00
yichin 95116252c8 save 2019-05-27 17:54:29 +08:00
yichin 28e8a66221 save 2019-05-27 17:26:58 +08:00
yichin 3249e7e1e2 save 2019-05-27 14:03:13 +08:00
yichin d5d97db086 fix bug 2019-05-27 13:28:16 +08:00
yichin c806a7e09f fix bug 2019-05-27 12:47:07 +08:00
yichin 95e563e04f fix bug 2019-05-27 11:53:41 +08:00
Ta-Shun Su 747ebf5f8b impl debug instruction 2019-05-27 11:15:56 +08:00
yichin fb942c8e40 more debug instruction 2019-05-27 11:10:00 +08:00
yichin fdc2f05d46 add led signal 2019-05-27 11:04:23 +08:00
Ta-Shun Su 3c2823cc13 save 2019-05-27 10:57:58 +08:00
yichin 9ba9131a51 Merge remote-tracking branch 'origin/neuliveSTI/1210' into neuliveSTI/1210 2019-05-27 10:25:28 +08:00
yichin bd64c60b40 save 2019-05-27 10:25:13 +08:00
Ta-Shun Su bb7e609665 add gptimer python 2019-05-27 10:24:43 +08:00
Ta-Shun Su 9c4794c868 save 2019-05-25 20:56:41 +08:00
Ta-Shun Su 019c32faf5 add error 2019-05-25 20:29:04 +08:00
Ta-Shun Su 96b6e4d1b9 save 2019-05-25 19:54:06 +08:00
yichin 105d01e636 save 2019-05-24 19:02:16 +08:00
yichin 71fcc98862 save 2019-05-24 18:29:46 +08:00
yichin c63656ac97 save 2019-05-24 17:39:06 +08:00
Ta-Shun Su 47a24ccef3 Merge remote-tracking branch 'origin/neuliveSTI/1210' into neuliveSTI/1210 2019-05-24 16:36:30 +08:00
Ta-Shun Su 2ee3abf193 improve devlib/util.py 2019-05-24 16:35:25 +08:00
Ta-Shun Su d9039070ad save 2019-05-24 16:32:01 +08:00
yichin f69fd4a40f save 2019-05-24 16:29:32 +08:00
yichin a6287ad7e3 fix bug 2019-05-24 15:12:19 +08:00
65 changed files with 2742 additions and 2344 deletions
+4 -1
View File
@@ -5,4 +5,7 @@ xdctools_*/
ccsv8/
# CSS build files
FlashROM/
FlashROM/
# python cache
__pycache__/
+3
View File
@@ -0,0 +1,3 @@
<component name="DependencyValidationManager">
<scope name="Driver" pattern="file[BioProCC2650]:simplelink/ble_sdk_2_02_02_25/src/boards/BOOSTXL_CC2650MA/*||file[BioProCC2650]:simplelink/ble_sdk_2_02_02_25/src/boards/CC2650_LAUNCHXL/*||file[BioProCC2650]:tirtos_cc13xx_cc26xx_2_21_01_08/products/tidrivers_cc13xx_cc26xx_2_21_01_01/packages/ti/drivers//*" />
</component>
Binary file not shown.
+205 -1
View File
@@ -13,27 +13,43 @@ BioPro Device
`simplelink/ble_sdk_2_02_02_25/src/examples/simple_peripheral/cc26xx/app/main.c`
### Current project
### Current project and state
1. Elite
`simplelink/ble_sdk_2_02_02_25/src/examples/simple_peripheral/cc26xx/app/headstage/headstage_tni.h`
**branch**
2. Neulive 1.2
`simplelink/ble_sdk_2_02_02_25/src/examples/simple_peripheral/cc26xx/app/headstage/headstage_uni.h`
**branch**
`neulive1.2/*`
3. Neulive 1.3
`simplelink/ble_sdk_2_02_02_25/src/examples/simple_peripheral/cc26xx/app/headstage/headstage_neulive.h`
**branch**
4. EliteZM
`simplelink/ble_sdk_2_02_02_25/src/examples/simple_peripheral/cc26xx/app/headstage/headstage_zm.h`
**branch**
`elite_zm/*`
5. NeuliveSTI
`simplelink/ble_sdk_2_02_02_25/src/examples/simple_peripheral/cc26xx/app/headstage/headstage_sti.h`
**branch**
`neuliveSTI/*`
### Notable source code
@@ -58,6 +74,194 @@ major source code path:
`simplelink/ble_sdk_2_02_02_25/src/examples/host_test/cc26xx/app/main.c`
**branch**
`host_test/master`
`release/host_test-*`
-----------------------------------------------
How to install this project in your PC
--------------------------------------
### install CCStudio
#### Prerequisite:
anti-virus software might cause some problems, disable it while installing is recommended.
#### Install CCS (Online install)
1. [code composer studio](http://processors.wiki.ti.com/index.php/Download_CCS) :
choose the latest version (we use 8.2.0.00007, Online Installer, as example) of Code Composer Studio.
2. run installer
3. accept the license
4. install at folder `c:/ti`
5. select all Processor Support
6. select all Debug Probes.
7. Finish. Allow the network access if the firewall jumps a warning dialog.
Wait for the install process......
#### Offline install
1. [code composer studio](http://processors.wiki.ti.com/index.php/Download_CCS) :
choose the latest version (we use 8.2.0.00007, Offline Installer) of Code Composer Studio.
2. Unzip it
3. Open the folder `CCS8.2.0.00007_win32` -> Open sub-folder `CCS8.2.0.00007_win32`
4. run installer *ccs_setup_8.2.0.00007*
5. accept the license
6. install at folder `c:/ti`
7. select all Processor Support
8. select all Debug Probes
9. Finish. Wait for the install process......
10. accept `Blackhawk Control` dialog popped out during the process
(we will not use this directly)
11. select options to create desktop shortcut and launch CCStudio
#### After install, update the CCStudio
1. at the first launch, CCStudio will ask you to select a directory as workspace. Use the default. -> Launch
2. help -> check for updates -> select all available updates -> next
3. accept the licenses -> finish -> wait for the installation...... -> Restart Now
### install BLE STACK
1. [BLE STACK](http://www.ti.com/tool/BLE-STACK):
choose `BLE-STACK-2-2-2` Free version.
(a TI account is required)
1. at the *U.S. Government export approval* page,
check all your information and submit then start to download.
2. run *ble_sdk_2_02_02_25_setup*
3. accept the license agreement
4. use the default installation directory `C:\ti\simplelink` -> wait for the install process......
5. **TI-RTOS for CC13xx and CC26xx Wireless MCUs Setup Wizard** will jump out -> next
at the same time, *ble_sdk_2_02_02_25_setup* will still be running, don't close the window
6. accept the license agreement
7. use the default installation directory `C:/ti` -> wait for the install process......
8. after **TI-RTOS for CC13xx and CC26xx Wireless MCUs Setup Wizard** has been install.
keep waiting for *ble_sdk_2_02_02_25_setup* to process
9. finish
### First run CCStudio and setting
1. start CCStudio
2. File -> import -> C/C++ -> CCS Projects -> next
3. Select search-directory `C:/ti/ble_sdk_2_02_02_25/examples/cc2650lp/simple_peripheral/ccs` -> OK
4. select all discovered projects -> finish
5. right click `simple_peripheral_cc2650lp_app` -> Properties -> Products -> **XDCtools version: 3.32.2.25_core**
6. remember to select **TI-RTOS for CC13xx and CC26xx: 2.21.1.08** and **Other Repositories: C:/to/ccsv8/ccs_base**
7. Project -> Tool-chain: **Compiler version: TI v18.1.3.LTS**
8. apply amd close
9. right click *simple_peripheral_cc2650lp_stack* -> Properties -> Products -> select all
10. Project -> Tool-chain: **compiler version: TI v18.1.3.LTS**
11. Click *build* and it's done
### clone this project
#### with Command line interface (git-bash)
1. `cd c:`
2. rename ti directory
`mv ti ti_backup`
3. clone our project.
`git clone URL ti`, where URL is our project url on gitlab.
4. move CCStudio back to ti directory
`mv -t ti ti_backup/ccsv8 ti_backup/xdctools-*`
5. open CCStudio and rebuild your project, check it work as normal.
### Optional
#### install git if you don't install it
* https://git-scm.com/download/win
* choose corresponding version for your computer from 'Git for Windows Setup'
#### doxygen: tool to help documenting code
* download from main page http://www.doxygen.nl/download.html
* according to different OS, download corresponding version.
* press keyboard 'ctrl' + 'shift' + 'a' to search external tool, select 'external tools-setting'
* add external tool by pressing '+'
* name this external tool in the column 'name'
* set the path of doxygen execute file in the column 'program'
* set the repository we want to generate document automatically in the column 'working directory'
* set hotkey of doxygen to run : 'File' -> 'Setting' -> 'Keymap' -> 'external tools'
* press the hotkey to run doxygen
### Troubleshooting
* jump a dialog with **MSVC components failed to install.
Please install executables manually from c:/ti/ccsv8/installers before using CCS**
ignore it.
* jumps a warning dialog of Windows Defender
Allow the network access.
-----------------------------------------------
Copyright (c) 2019. BioPro. Scientific.
-50
View File
@@ -1,50 +0,0 @@
from devlib.util import print_instruction
STI_INSTRUCTION = {
'GLOBAL': '3b001#header#;1b0;12bCURRENT',
'LOCAL': '3b010#header;1b0;4b>CHANNEL;3b>STI_MODE;1b>PRECISION;12b>STI_FREQ;10b>STI_PW;10b>STI_PW_IPI;10b>STI_NUM'
}
STI_PARAMETER = {
'CURRENT': 10,
'CHANNEL': 0,
'STI_MODE': 3,
'PRECISION': 0,
'STI_FREQ': 10,
'STI_PW': 10,
'STI_PW_IPI': 10,
'STI_NUM': 10,
}
NEULIVE_INSTRUCTION = {
'RIS': '3b101#header#;2b0;3b>LB;2b0;1bCH;1bFS;3b>WF;5b>TV;4b>PM;4b>NM;4b>SR',
'UMC': '3b001#umc_parameter;3b>AG;4b>PW;6b>TT;2b>SB;6b>TF;1bCA;1bCB;1bCC;1bCD;4b>CHA;4b>CHB;4b>CHC;4b>CHD'
}
NEULIVE_PARAMETER = {
'LB': 0, # LOW BAND FREQEUNCY
'CH': 0, # CHOPPER
'FS': 0, # FAST SETTLE
'WF': 1, # WAVEFORM : POS, NEG, P2N...etc.
'TV': 0, # STIMULATION VOLTAGE
'PM': 0, # P CHANNEL SELECT
'NM': 0, # N CHANNEL SELECT
'SR': 0, # ADC SAMPLING RATE
'AG': 5, # AMP GAIN
'PW': 0, # PULSE WIDTH
'TT': 9, # STIMULATION TIMES
'SB': 3, # STIMULATION BEHAVIOR
'TF': 10, # STIMULATION FREQUENCY
'CA': 1, # AMP CHANNEL A ENABLE
'CB': 0, # AMP CHANNEL B ENABLE
'CC': 0, # AMP CHANNEL C ENABLE
'CD': 0, # AMP CHANNEL D ENABLE
'CHA': 0, # AMP CHANNEL A
'CHB': 1, # AMP CHANNEL B
'CHC': 2, # AMP CHANNEL C
'CHD': 3, # AMP CHANNEL D
}
print_instruction(NEULIVE_INSTRUCTION['RIS'],NEULIVE_PARAMETER)
print_instruction(NEULIVE_INSTRUCTION['UMC'],NEULIVE_PARAMETER)
+99 -7
View File
@@ -121,6 +121,75 @@ def append_buffer(buffer: List[int], shift: int, width: int, value: int, little_
return (shift + width) % 8
class DeviceInstruction:
"""
**Instruction Send**
raw byte data format. ::
| 0 | 1 | 2 | 3 |
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
-----------------------------------------------------------------
| RIS | ID | | LEN | ............................. real instruction send
| VIS | ID | OPER | LEN | ............................. virtual instruction send
| CIS | ID | OPER | LEN | ............................. command instruction send
ID
chip ID
RIS
header for real instruction type. (header=3)
VIS
header for virtual instruction type. (header=C)
CIS
header for command instruction type. (header=7)
OPER
operator/command
LEN, length
command/data length in bytes
"""
TYP_RIS = 0x30
"""header for real instruction type.
It is real instruction send to the chip which contain the chip configuration parameter.
"""
TYP_VIS = 0xC0
"""header for virtual instruction type.
It is virtual instruction send to the controller chip to control the chip.
"""
TYP_CIS = 0x70
"""header for command instruction type.
It is command send to the controller chip for the special purpose.
"""
VIS_RST = 0xF0
"""reset virtual instruction"""
VIS_ASK = 0x30
"""ask in virtual instruction"""
VIS_STI = 0xC0
"""stimulation on virtual instruction"""
VIS_FUH = 0x90
"""flush virtual instruction"""
VIS_INT = 0x60
"""interrupt virtual instruction"""
VIS_CAL = 0xA0
"""device calling"""
CIS_VOLT = 0x10
"""get device battery voltage level"""
class InstructionContentWidth:
"""instruction width.
@@ -558,25 +627,48 @@ def parse_instruction(expr: str) -> InstructionContent:
return ins_type(width, expr, **ins_argv, comment=comment)
def eval_instruction(expr: str, context: Dict[str, Any], buffer: Optional[List[int]] = None) -> List[int]:
ins = parse_instruction(expr)
def eval_instruction(expr: Union[str, int], context: Dict[str, Any], buffer: Optional[List[int]] = None) -> List[int]:
if buffer is None:
buffer = []
ins.build_instruction(context, buffer, 0)
if isinstance(expr, str):
ins = parse_instruction(expr)
ins.build_instruction(context, buffer, 0)
elif isinstance(expr, int):
if expr in (DeviceInstruction.VIS_RST,
DeviceInstruction.VIS_ASK,
DeviceInstruction.VIS_STI,
DeviceInstruction.VIS_FUH,
DeviceInstruction.VIS_INT,
DeviceInstruction.VIS_CAL):
buffer.extend([DeviceInstruction.TYP_VIS, expr])
else:
raise RuntimeError('unknown expr code : ' + str(expr))
else:
raise RuntimeError('illegal expr type : ' + str(expr))
return buffer
def print_instruction(expr: str, context: Dict[str, Any], append_ris_type: bool = True):
def print_instruction(expr: Union[str, int],
context: Dict[str, Any],
append_ris_type: bool = True,
c_style_uint8_array: Optional[str] = None):
buffer = []
eval_instruction(expr, context, buffer)
if append_ris_type:
if append_ris_type and isinstance(expr, str):
length = len(buffer)
buffer.insert(0, 0x30)
buffer.insert(1, length)
print(hex_line(buffer))
if c_style_uint8_array is None:
print(hex_line(buffer))
else:
for i, v in enumerate(buffer):
print(c_style_uint8_array, '[%d]' % i, ' = ', '0x%02X' % v, ';', sep='')
+22
View File
@@ -0,0 +1,22 @@
CPU_FREQUENCY = 48e6
def headstage_gptimer_get_frequency_load_value(frequency: float) -> int:
load = int(CPU_FREQUENCY / frequency) - 1
if load < 0xFFFF:
return load
else:
return 0xFA0000 | int(load / 250) - 1
def headstage_gptimer_get_timeout_load_value(timeout_us: int) -> int:
load = int(timeout_us * CPU_FREQUENCY / 1e6) - 1
if load < 0xFFFF:
return load
else:
return 0xFA0000 | int(load / 250) - 1
print('0x%06X' % headstage_gptimer_get_frequency_load_value(0.8))
+115
View File
@@ -0,0 +1,115 @@
from typing import Dict, Any
from devlib.util import print_instruction, DeviceInstruction
CHANNEL_STI_0 = 0
CHANNEL_STI_1 = 1
STI_WAVEFORM_POS = 0x00
STI_WAVEFORM_NEG = 0x01
STI_WAVEFORM_P2N = 0x02
STI_WAVEFORM_N2P = 0x03
STI_PRECISION_10 = 0
STI_PRECISION_01 = 1
STI_INSTRUCTION = {
'GLOBAL': '5b11111;2b0#GV;12bCURRENT',
'LOCAL': '5b11111;2b01#LV;3b>CHANNEL;1b>PRECISION;3b>STI_MODE;12b>STI_FREQ;10b>STI_PW;10b>STI_PW_IPI;10b>STI_NUM',
'CHANNEL': '5b11111;2b10#CE;ba0;ba1;ba2;ba3;ba4;ba5;ba6;ba7;ba8;ba9;baa;bab;bac;bad;bae;baf'
}
DEFAULT_PARAMETER = {
'CURRENT': 10, # uA
'CHANNEL': CHANNEL_STI_0,
'STI_MODE': STI_WAVEFORM_POS,
'PRECISION': STI_PRECISION_10,
'STI_FREQ': 1000, # Hz
'STI_PW': 100, # us
'STI_PW_IPI': 50, # us
'STI_NUM': 900,
}
def validate_frequency_parameter(parameter: Dict[str, Any]) -> bool:
p = int(parameter['PRECISION'])
f = int(parameter['STI_FREQ'])
w = int(parameter['STI_PW'])
i = int(parameter['STI_PW_IPI'])
return 1e6 * (1 if p == 0 else 10) / f >= 2 * w + i
def get_channel_enable_parameter(*channel: int):
return {
'a0': 1 if 0 in channel else 0,
'a1': 1 if 1 in channel else 0,
'a2': 1 if 2 in channel else 0,
'a3': 1 if 3 in channel else 0,
'a4': 1 if 4 in channel else 0,
'a5': 1 if 5 in channel else 0,
'a6': 1 if 6 in channel else 0,
'a7': 1 if 7 in channel else 0,
'a8': 1 if 8 in channel else 0,
'a9': 1 if 9 in channel else 0,
'aa': 1 if 10 in channel else 0,
'ab': 1 if 11 in channel else 0,
'ac': 1 if 12 in channel else 0,
'ad': 1 if 13 in channel else 0,
'ae': 1 if 14 in channel else 0,
'af': 1 if 15 in channel else 0,
}
# -------------------------------------------------------------------------------------------------------------------- #
STI_PARAMETER_0 = {
'CURRENT': 10, # uA
'CHANNEL': CHANNEL_STI_0,
'STI_MODE': STI_WAVEFORM_POS,
'PRECISION': STI_PRECISION_10,
'STI_FREQ': 10, # Hz
'STI_PW': 10, # us
'STI_PW_IPI': 10, # us
'STI_NUM': 900,
}
STI_PARAMETER_1 = {
'CURRENT': 10, # uA
'CHANNEL': CHANNEL_STI_1,
'STI_MODE': STI_WAVEFORM_NEG,
'PRECISION': STI_PRECISION_10,
'STI_FREQ': 10, # Hz
'STI_PW': 10, # us
'STI_PW_IPI': 10, # us
'STI_NUM': 900,
}
print_instruction(STI_INSTRUCTION['GLOBAL'], STI_PARAMETER_0, append_ris_type=False)
valid_channel_0 = validate_frequency_parameter(STI_PARAMETER_0)
valid_channel_1 = validate_frequency_parameter(STI_PARAMETER_1)
enable_channel = []
if not valid_channel_0:
print('invalidate parameter')
else:
print('----')
print_instruction(STI_INSTRUCTION['LOCAL'], STI_PARAMETER_0, append_ris_type=False)
enable_channel.append(0)
if not valid_channel_1:
print('invalidate parameter')
else:
print('----')
print_instruction(STI_INSTRUCTION['LOCAL'], STI_PARAMETER_1, append_ris_type=False)
enable_channel.append(1)
if valid_channel_0 or valid_channel_1:
print('----')
print_instruction(STI_INSTRUCTION['CHANNEL'], get_channel_enable_parameter(*enable_channel), append_ris_type=False)
print('--sti--')
print_instruction(DeviceInstruction.VIS_STI, {})
print('--int--')
print_instruction(DeviceInstruction.VIS_INT, {})
+133
View File
@@ -0,0 +1,133 @@
from typing import Dict, Any
from devlib.util import print_instruction, DeviceInstruction
CHANNEL_STI_0 = 0
CHANNEL_STI_1 = 1
STI_WAVEFORM_POS = 0x00
STI_WAVEFORM_NEG = 0x01
STI_WAVEFORM_P2N = 0x02
STI_WAVEFORM_N2P = 0x03
STI_PRECISION_10 = 0
STI_PRECISION_01 = 1
STI_NUM_INFINITE = 1000
STI_INSTRUCTION = {
'GLOBAL': '3b001#header#;1b0;12bCURRENT',
'LOCAL': '3b010#header;1b0;4b>CHANNEL;3b>STI_MODE;1b>PRECISION;12b>STI_FREQ;10b>STI_PW;10b>STI_PW_IPI;10b>STI_NUM'
}
DEFAULT_PARAMETER = {
'CURRENT': 10, # uA
'CHANNEL': CHANNEL_STI_0,
'STI_MODE': STI_WAVEFORM_POS,
'PRECISION': STI_PRECISION_10,
'STI_FREQ': 1000, # Hz
'STI_PW': 100, # us
'STI_PW_IPI': 50, # us
'STI_NUM': STI_NUM_INFINITE,
}
def validate_frequency_parameter(parameter: Dict[str, Any]) -> bool:
p = int(parameter['PRECISION'])
f = int(parameter['STI_FREQ'])
w = int(parameter['STI_PW'])
i = int(parameter['STI_PW_IPI'])
return 1e6 * (1 if p == 0 else 10) / f >= 2 * w + i
SPIN_TIMEOUT = [
(10, 53),
(20, 106),
(30, 160),
(40, 214),
(50, 265),
(60, 319),
(70, 374),
(80, 427),
(100, 533),
(150, 800),
(200, 1066),
(300, 1600),
(400, 2133),
(500, 2666),
(1000, 5332),
]
def get_spin_timeout_value(timeout_us: int) -> int:
if timeout_us == 0:
return 0
elif timeout_us <= SPIN_TIMEOUT[0][0]:
return SPIN_TIMEOUT[0][1]
elif timeout_us >= SPIN_TIMEOUT[-1][0]:
return SPIN_TIMEOUT[-1][1]
else:
for i in range(len(SPIN_TIMEOUT)):
t0 = SPIN_TIMEOUT[i][0]
v0 = SPIN_TIMEOUT[i][1]
if timeout_us == t0:
return v0
t1 = SPIN_TIMEOUT[i + 1][0]
v1 = SPIN_TIMEOUT[i + 1][1]
if t0 < timeout_us < t1:
dt = t1 - t0
return int((t1 - timeout_us) * v0 / dt + (timeout_us - t0) * v1 / dt)
raise RuntimeError()
# -------------------------------------------------------------------------------------------------------------------- #
STI_PARAMETER_0 = {
'CURRENT': 10, # uA
'CHANNEL': CHANNEL_STI_0,
'STI_MODE': STI_WAVEFORM_POS,
'PRECISION': STI_PRECISION_10,
'STI_FREQ': 10, # Hz
'STI_PW': 10, # us
'STI_PW_IPI': 10, # us
'STI_NUM': STI_NUM_INFINITE,
}
STI_PARAMETER_1 = {
'CURRENT': 10, # uA
'CHANNEL': CHANNEL_STI_1,
'STI_MODE': STI_WAVEFORM_NEG,
'PRECISION': STI_PRECISION_10,
'STI_FREQ': 10, # Hz
'STI_PW': 10, # us
'STI_PW_IPI': 10, # us
'STI_NUM': STI_NUM_INFINITE,
}
print_instruction(STI_INSTRUCTION['GLOBAL'], STI_PARAMETER_0, append_ris_type=False)
if not validate_frequency_parameter(STI_PARAMETER_0):
print('invalidate parameter')
else:
print('----')
print_instruction(STI_INSTRUCTION['LOCAL'], STI_PARAMETER_0, append_ris_type=False)
if not validate_frequency_parameter(STI_PARAMETER_1):
print('invalidate parameter')
else:
print('----')
print_instruction(STI_INSTRUCTION['LOCAL'], STI_PARAMETER_1, append_ris_type=False)
print('--sti--')
print_instruction(DeviceInstruction.VIS_STI, {})
print('--int--')
print_instruction(DeviceInstruction.VIS_INT, {})
-1
View File
@@ -1 +0,0 @@
*.txt
+4 -525
View File
@@ -1,528 +1,7 @@
"""
purpose:
in order to analyze the data loss of bluetooth, a small code is needed.
Guess that there are three type of data loss. In order to prove this idea,
several tests are needed
types of data loss:
1. packet loss:
bluetooth notification does not need any negotiation.
if there is any packet loss during the connection,
it will not be lost forever
2. program delay causes loss in client(headstage):
too many effort on data packaging, it would cause
data delay
3. program delay causes loss in host(controller):
...todo and need to define
Assume that we have lost several bytes data. We want to analyze the type of data lost.
method:
compare ramp data with time stamp, there are several conditions
if data_delta * 1 / sampling_rate == time_delta:
this should be packet loss
else
this should be program delay
method to coped with the corresponding problem:
1. try 'Indication' to check data loss is reduced or not.
2. modified the procedure of data packaging
3. after the upper two problems are excluded, this problem should be left over
"""
import os.path
import sys
from collections import Counter
from typing import List, Optional, Dict, Set, Any
class Options:
def __init__(self):
self.skip = False
self.round = 2
self.overflow_pow: Optional[int] = None
# print options
self.quiet = False
# graph options
self.graph: Optional[str] = None
self.graph_log_scale = False
self.graph_save_path: Optional[str] = None
# fft graph options
self.fft_x_log = False
self.fft_y_norm = False
self.fft_channel = 0
@staticmethod
def print_help():
prg = sys.argv[0]
print(prg, '[OPTIONS]', 'FILE', '...')
print()
print('OPTIONS:')
print(' -h, --help : print help')
print(' --skip : skip if FILE not found')
print(' --round VALUE : floating number round')
print(' --overflow VALUE : overflow number. 2^VALUE')
print()
print('OPTIONS (print):')
print(' -q : do not print table')
print()
print('OPTIONS (graph):')
print(' --graph TYPE : use matplotlib to generate graph. could be:')
print(' ramp : ramp data, calculate value miss')
print(' fft : sin wave data, calculate fft')
print(' --graph-log-scale :')
print(' --graph-save PATH : save graph file path')
print()
print('OPTIONS (graph=fft):')
print(' --fft-channel CH : filter channel')
print(' --fft-log : log x-axis')
print(' --fft-norm : log x-axis normalize')
print(' --fft [opt,...] : above')
print()
print('ARGUMENTS:')
print(' FILE : txt data file')
print()
class Result:
def __init__(self, data_file: str, options: Options):
# data file information
self.data_file = data_file
self.date_time: Optional[str] = None
self.device_name: Optional[str] = None
self.device_address: Optional[str] = None
self.parameter: Dict[str, str] = {}
self.channel: Set[int] = set()
self.total_duration: float = 0.0
# analysis data
self.data_count = 0
self.time_delta_counter = Counter()
self.value_delta_counter = Counter()
# analysis options
self.round = options.round
self.overflow: Optional[int] = None
if options.overflow_pow is not None:
self.overflow = 2 ** options.overflow_pow
# temp data
self._prev_time: Optional[float] = None
self._prev_value: Optional[int] = None
self._close = False
@property
def sample_rate(self) -> int:
try:
sample_rate = self.parameter['SAMPLE_RATE']
except KeyError as e:
raise RuntimeError('data file do not contain SAMPLE_RATE') from e
try:
return int(sample_rate)
except ValueError as e:
raise RuntimeError('data file SAMPLE_RATE value not a value : ' + str(sample_rate)) from e
def update(self, time: float, channel: int, value: int):
if self._close:
raise RuntimeError('closed')
self.data_count += 1
if self._prev_time is not None:
delta = round(time - self._prev_time, self.round)
self.time_delta_counter[delta] += 1
if self._prev_value is not None:
delta = value - self._prev_value
self.value_delta_counter[delta] += 1
self._prev_time = time
self.channel.add(channel)
self._prev_value = value
self.total_duration = time
def close(self):
self._close = True
if self.overflow is not None:
self.value_delta_counter[1] += self.value_delta_counter[1 - self.overflow]
del self.value_delta_counter[1 - self.overflow]
i = 2
while i - self.overflow in self.value_delta_counter:
self.value_delta_counter[i] += self.value_delta_counter[i - self.overflow]
del self.value_delta_counter[i - self.overflow]
i += 1
def calculate(txt_file: str, options: Options) -> Result:
if not os.path.exists(txt_file):
raise FileNotFoundError(txt_file)
result = Result(txt_file, options)
parsing_state = 0
with open(txt_file) as _file:
for line, content in enumerate(_file): # type: int, str
content = content.strip()
if len(content) == 0:
continue
if parsing_state == 0:
if content.startswith('#'):
if result.date_time is None:
result.date_time = content[1:].strip()
elif content.startswith('# device_name'):
result.device_name = content[len('# device_name'):].strip()
elif content.startswith('# mac_address'):
result.device_address = content[len('# mac_address'):].strip()
elif content.startswith('# parameter'):
parsing_state = 1
elif parsing_state == 1:
if content.startswith('#'):
if content.startswith('# time_stamp'):
parsing_state = 2
else:
part = content[2:].split(' ', maxsplit=2)
result.parameter[part[0]] = part[1]
elif parsing_state == 2:
if content.startswith('#'):
continue
part = content.split(' ', maxsplit=3)
try:
time = part[0]
channel = part[1]
value = part[2]
except IndexError:
print('@%d' % (line + 1), 'incomplete data', ':', content)
continue
check_pass = True
try:
time = float(time)
except ValueError:
print('@%d' % (line + 1), 'incomplete time', ':', time)
check_pass = False
try:
channel = int(channel)
except ValueError:
print('@%d' % (line + 1), 'incomplete channel', ':', channel)
check_pass = False
try:
value = int(value)
except ValueError:
print('@%d' % (line + 1), 'incomplete value', ':', value)
check_pass = False
if check_pass:
result.update(time, channel, value)
result.close()
return result
def print_result(result: Result, options: Options):
def print_table(counter: Dict[Any, Any], key_format='%10d', value_format='%d'):
f = ' %s : %s' % (key_format, value_format)
for k in sorted(counter.keys()):
print(f % (k, counter[k]))
if not options.quiet:
print(result.data_file)
print('data_count', result.data_count)
print('channel', ' '.join(list(map(str, sorted(result.channel)))))
try:
sample_rate = result.sample_rate
print('sample_rate [1/s]', sample_rate)
print('1/sample_rate [ms]', 1000 / sample_rate)
except RuntimeError:
print('sample_rate', '(E)')
print('time_delta')
print_table(result.time_delta_counter, '%10.2f')
print()
print('value_delta')
print_table(result.value_delta_counter)
print()
# packet miss rate
#
if options.graph == 'ramp':
delta_value = list(filter(lambda it: it > 0, result.value_delta_counter))
total = sum(map(lambda it: it * result.value_delta_counter[it], delta_value))
miss = sum(map(lambda it: (it - 1) * result.value_delta_counter[it], delta_value))
print('value_miss (ramp)', '%d/%d' % (miss, total), '%.2f%%' % (100 * miss / total))
valid_time = list(filter(lambda it: it < 50, result.time_delta_counter))
total_valid_t = sum(map(lambda it: it * result.time_delta_counter[it], valid_time))
print('time_waste (ramp)', '%d/%d' % (total_valid_t, result.total_duration), '%.2f%%' % ( 100 * total_valid_t / result.total_duration))
timesofwaste = list(filter(lambda it: it > 50, result.time_delta_counter))
timesintotal = sum(map(lambda it: result.time_delta_counter[it], timesofwaste))
print('waste time occur times (ramp)', '%d' % timesintotal)
print()
paint_ramp_result(result, options)
elif options.graph == 'fft':
paint_fft_result(result, options)
def paint_fft_result(result: Result, options: Options):
import matplotlib.pyplot as plt
import numpy as np
from scipy import signal
from scipy.interpolate import interp1d
from scipy.fftpack import fft
time_seq = []
value_seq = []
time_offset = None
total_duration = 0.0
with open(result.data_file) as _file:
for line in _file:
line = line.strip()
if len(line) == 0 or line.startswith('#'):
continue
else:
part = line.split(' ', maxsplit=3)
channel = int(part[1])
if channel == options.fft_channel:
time = float(part[0])
if time_offset is None:
time_seq.append(0.0)
time_offset = time
else:
total_duration = time - time_offset
time_seq.append(time - time_offset)
value_seq.append(int(part[2]))
if len(time_seq) == 0:
raise RuntimeError('empty channel data : ' + str(options.fft_channel))
plt.figure(1)
f1, pxx_den = signal.periodogram(value_seq, 1e3)
plt.semilogy(f1, pxx_den)
plt.ylim([1e-7, 1e3])
plt.xlabel('frequency [hz]')
plt.ylabel('PSD[v**2/Hz')
plt.figure(2)
sample_rate = result.sample_rate
time_delta = 1 / sample_rate
total_time_step = int(total_duration / (time_delta * 1000))
f = interp1d(time_seq, value_seq, copy=False)
t = np.linspace(0, total_duration, total_time_step)
fft_result = fft(f(t))
fft_result = fft_result[:len(fft_result) // 2]
fft_x = np.linspace(0, 1.0/(2.0*time_delta), len(fft_result)//2)
if options.fft_x_log:
fft_x = np.log10(fft_x)
if options.fft_y_norm:
fft_result /= sum(fft_result)
plt.plot(fft_x, 2.0 / len(fft_result) * np.abs(fft_result[0:len(fft_result)//2]))
if options.graph_save_path is not None:
plt.savefig(options.graph_save_path, dpi=600)
else:
plt.show()
def paint_ramp_result(result: Result, options: Options):
import matplotlib.pyplot as plt
fig, (at, av) = plt.subplots(2, 1)
time_delta_data = list(result.time_delta_counter)
expect_time_delta = 1000 / result.sample_rate
time_delta_bins = int((max(time_delta_data) - min(time_delta_data)) / expect_time_delta)
time_delta_weight = [result.time_delta_counter[k] for k in time_delta_data]
at.hist(time_delta_data,
bins=time_delta_bins,
weights=time_delta_weight,
log=options.graph_log_scale,
align='left')
value_delta_data = list(result.value_delta_counter)
value_delta_bins = max(value_delta_data) - min(value_delta_data)
value_delta_weight = [result.value_delta_counter[k] for k in value_delta_data]
av.hist(value_delta_data,
bins=value_delta_bins,
weights=value_delta_weight,
log=options.graph_log_scale,
align='left')
fig.tight_layout()
if options.graph_save_path is not None:
plt.savefig(options.graph_save_path, dpi=600)
else:
plt.show()
def main(argv: List[str]):
"""
:param argv:
:return:
"""
# df = pd.read_csv("C:/Users/yichin/Downloads/last-2019-07-18-16-30-15-7.csv", sep=",", skiprows=12, header=None)
# sel_df = pd.DataFrame(df)
# column, row = sel_df.shape
# sel_df = sel_df.fillna(value=0)
# delta_df = sel_df.diff(periods=1)
# delta_df = delta_df.fillna(value=0)
# delta_df = delta_df.drop(column - 1)
# delta_df.set_axis(['time_delta', 'data_delta'], axis='columns', inplace=True)
o = Options()
i = 0
while i < len(argv):
arg = argv[i]
if arg in ('-h', '--help'):
o.print_help()
return
elif arg == '--skip':
o.skip = True
i += 1
elif arg == '--round':
o.round = int(argv[i + 1])
i += 2
elif arg.startswith('--round='):
o.round = int(arg[len('--round='):])
i += 1
elif arg == '--overflow':
o.overflow_pow = int(argv[i + 1])
i += 2
elif arg.startswith('--overflow='):
o.overflow_pow = int(arg[len('--overflow='):])
i += 1
elif arg == '-q':
o.quiet = True
i += 1
elif arg == '--graph':
o.graph = argv[i + 1]
i += 2
elif arg.startswith('--graph='):
o.graph = arg[len('--graph='):]
i += 1
elif arg == '--graph-log-scale':
o.graph_log_scale = True
i += 1
elif arg == '--graph-save':
o.graph_save_path = argv[i + 1]
i += 2
elif arg.startswith('--graph-save='):
o.graph = arg[len('--graph-save='):]
i += 1
elif arg == '--fft-channel':
o.fft_channel = int(argv[i + 1])
i += 2
elif arg.startswith('--fft-channel='):
o.fft_channel = int(arg[len('--fft-channel='):])
i += 1
elif arg == '--fft-log':
o.fft_x_log = True
i += 1
elif arg == '--fft-norm':
o.fft_y_norm = True
i += 1
elif arg.startswith('--fft'):
if arg == '--fft':
c = argv[i + 1]
i += 2
elif arg.startswith('--fft='):
c = arg[len('--fft='):]
i += 1
else:
raise ValueError('unknown options : ' + arg)
for a in c.split(','):
if a == 'log':
o.fft_x_log = True
elif a == 'norm':
o.fft_y_norm = True
elif a.startswith('channel='):
o.fft_channel = int(a[len('channel='):])
else:
raise ValueError('unknown options : --fft-' + a)
elif arg.startswith('-'):
raise ValueError('unknown options : ' + arg)
else:
i += 1
try:
result = calculate(arg, o)
except FileNotFoundError:
if o.skip:
continue
else:
raise
else:
print_result(result, o)
def main():
with open('C:/ti/python_test_code/uni/att_notify.psd', 'r') as file:
print(file.read())
if __name__ == '__main__':
main(sys.argv[1:])
main()
+33
View File
@@ -0,0 +1,33 @@
from devlib.util import print_instruction
NEULIVE_INSTRUCTION = {
'RIS': '3b101#header#;2b0;3b>LB;4b0;1bCH;1bFS;3b>WF;5b>TV;4b>PM;4b>NM;4b>SR',
'UMC': '3b001#umc_parameter;3b>AG;4b>PW;6b>TT;2b>SB;6b>TF;1bCA;1bCB;1bCC;1bCD;4b>CHA;4b>CHB;4b>CHC;4b>CHD'
}
NEULIVE_PARAMETER = {
'LB': 0,
'CH': 0,
'FS': 0,
'WF': 0,
'TV': 0,
'PM': 15,
'NM': 0,
'SR': 0,
'AG': 5,
'PW': 0,
'TT': 0,
'SB': 1,
'TF': 3,
'CA': 1,
'CB': 0,
'CC': 0,
'CD': 0,
'CHA': 0,
'CHB': 1,
'CHC': 2,
'CHD': 3,
}
print_instruction(NEULIVE_INSTRUCTION['RIS'], NEULIVE_PARAMETER)
print_instruction(NEULIVE_INSTRUCTION['UMC'], NEULIVE_PARAMETER)
+98 -95
View File
@@ -1,15 +1,47 @@
import unittest
from random import randint
from typing import List, Optional
from typing import List, Optional, Tuple, Iterable
REC_CHANNEL_COUNT = 16
REC_CHANNEL_COUNT = 12
CHANNEL_INS2MUX = (10, 0, 1, 2, 3, 8, 7, 6, 5, 4, 9, 8)
'''index:ins -> value:mux'''
CHANNEL_MUX2INS = (1, 2, 3, 4, 9, 8, 7, 6, 5, 10, 0, 11)
'''index:mux -> value:ins'''
def to_channel_table(*channel: int) -> List[bool]:
return [i in channel for i in range(REC_CHANNEL_COUNT)]
def rearrange_channel_mux_table(channel_table: List[bool]) -> Optional[List[int]]:
def to_mux_channel(channel: Iterable[int], sort=False) -> List[int]:
ret = [CHANNEL_INS2MUX[ch] for ch in channel]
if sort:
ret.sort()
return ret
def to_ins_channel(channel: Iterable[int], sort=False) -> List[int]:
ret = [CHANNEL_MUX2INS[ch] for ch in channel]
if sort:
ret.sort()
return ret
def to_mux_channel_table(*channel: int) -> List[bool]:
return [CHANNEL_MUX2INS[i] in channel for i in range(REC_CHANNEL_COUNT)]
def to_ins_channel_table(*channel: int) -> List[bool]:
return [CHANNEL_INS2MUX[i] in channel for i in range(REC_CHANNEL_COUNT)]
def rearrange_channel_mux_table(channel_table: List[bool]) -> Tuple[int, Optional[List[int]]]:
enable_channel_number = 0
last_enable_channel = 0
@@ -19,14 +51,14 @@ def rearrange_channel_mux_table(channel_table: List[bool]) -> Optional[List[int]
enable_channel_number += 1
if enable_channel_number == 0:
return None
return 0, None
channel_mux = [0 for _ in range(REC_CHANNEL_COUNT)]
if enable_channel_number == 1:
channel_mux[0] = last_enable_channel
return channel_mux
return 1, channel_mux
next_enable_channel = last_enable_channel
channel_mux_index = last_enable_channel
@@ -57,131 +89,102 @@ def rearrange_channel_mux_table(channel_table: List[bool]) -> Optional[List[int]
channel_mux[channel_mux_index] = channel_mux[channel_mux_index + offset]
channel_mux_index -= 1
return channel_mux
return last_enable_channel + 1, channel_mux
def channel_used_count(channel_mux: List[int]):
def count_used_channel(channel_mux: List[int]):
ret = [0] * REC_CHANNEL_COUNT
channel_uc = [0] * 16
channel_sel = [0] * 16
for i in range(15):
for j in range(16):
if channel_mux[i] == j:
if channel_mux[i] != channel_mux[i+1]:
channel_uc[j] += 1
channel_sel[j] = j
for ch in channel_mux:
ret[ch] += 1
return channel_uc, channel_sel
return ret
def channel_table_transfer(channel_mux: List[bool]) -> Optional[List[bool]]:
channel_look_up_table = [1, 2, 3, 4, 9, 8, 7, 6, 5, 10, 0, 11]
true_channel = [False] * 16
for i in range(16):
if channel_mux[i]:
true_channel[channel_look_up_table[i]] = True
return true_channel
def expect_channel_count(*channel: int) -> List[int]:
channel_mux = to_mux_channel_table(*channel)
used, mux_arrange = rearrange_channel_mux_table(channel_mux)
if used == 0:
ins_arrange = to_ins_channel([])
else:
ins_arrange = to_ins_channel(mux_arrange[:used], sort=False)
return count_used_channel(ins_arrange)
def channel_table_tran(channel_mux: List[bool]):
channel_look_up_table = [2, 3, 4, 5, 10, 9, 8, 7, 6, 11, 1, 12]
channel_sel = [0] * 16
channel_index = 0
for i in range(16):
if channel_mux[i]:
channel_sel[channel_index] = channel_look_up_table[i]
channel_index += 1
channel_sel.sort(reverse=True)
return channel_sel, channel_index
def loop_repeat(col: List[int]) -> Iterable[int]:
while True:
yield from iter(col)
def channel_use_count(channel_sel: List[int], channel_index: int) -> Optional[List[int]]:
repeat_times = int(channel_sel[0] / channel_index)
remain_value = int(channel_sel[0] % channel_index)
ch_use_cnt = [0] * 16
for i in range(channel_index):
if i < remain_value:
ch_use_cnt[i] = remain_value + repeat_times
else:
ch_use_cnt[i] = repeat_times
return ch_use_cnt
def channel_count(*channel: int) -> List[int]:
if len(channel) == 0:
return [0] * REC_CHANNEL_COUNT
elif len(channel) == 1:
channel = channel[0]
return [1 if ch == channel else 0 for ch in range(REC_CHANNEL_COUNT)]
def count_channel_without_re(channel_mux: List[bool]) -> Optional[List[int]]:
channel_sel, channel_index = channel_table_tran(channel_mux)
ch_use_cnt = channel_use_count(channel_sel, channel_index)
for i in range(channel_index):
channel_sel[i] -= 1
print(channel_sel)
print(ch_use_cnt)
return ch_use_cnt
else:
channel_mux = to_mux_channel(channel, sort=True)
ret = [0] * REC_CHANNEL_COUNT
i = max(channel_mux) + 1
for ch in loop_repeat(channel_mux[::-1]):
ret[CHANNEL_MUX2INS[ch]] += 1
i -= 1
if i == 0:
break
def reverse_channel_table(original_ch: List[int]) -> Optional[List[int]]:
reverse_look_up_table = [10, 0, 1, 2, 3, 8, 7, 6, 5, 4, 9, 8]
reverse_ch = [0] * 16
for i in range(16):
if original_ch[i] != 0:
reverse_ch[reverse_look_up_table[i]] = original_ch[i]
return reverse_ch
def count_channel(channel_mux: List[bool]) -> Optional[List[int]]:
real_ch = channel_table_transfer(channel_mux)
ch_mux = rearrange_channel_mux_table(real_ch)
ch_count, ch_sel = channel_used_count(ch_mux)
reverse_ch = reverse_channel_table(ch_count)
reverse_ch.sort(reverse=True)
ch_sel.sort(reverse=True)
print(ch_sel)
print(reverse_ch)
return reverse_ch
return ret
class UniRearrangeMuxChannelTest(unittest.TestCase):
def test_empty_channel(self):
self.assertIsNone(rearrange_channel_mux_table(to_channel_table()))
i, a = rearrange_channel_mux_table(to_channel_table())
self.assertEqual(0, i)
self.assertIsNone(a)
def test_single_channel(self):
for _ in range(3):
c = randint(0, REC_CHANNEL_COUNT - 1)
expect = [c if i == 0 else 0 for i in range(REC_CHANNEL_COUNT)]
print(expect)
self.assertEqual(expect, rearrange_channel_mux_table(to_channel_table(c)))
self.assertTupleEqual((1, expect), rearrange_channel_mux_table(to_channel_table(c)))
def test_two_channel(self):
self.assertEqual([1, 7, 1, 7, 1, 7, 1, 7, 0, 0, 0, 0, 0, 0, 0, 0],
rearrange_channel_mux_table(to_channel_table(7, 1)))
self.assertEqual([2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
rearrange_channel_mux_table(to_channel_table(2, 1)))
self.assertEqual([3, 7, 2, 3, 7, 2, 3, 7, 0, 0, 0, 0, 0, 0, 0, 0],
rearrange_channel_mux_table(to_channel_table(7, 3, 2)))
self.assertTupleEqual((8, [1, 7, 1, 7, 1, 7, 1, 7, 0, 0, 0, 0]),
rearrange_channel_mux_table(to_channel_table(7, 1)))
self.assertTupleEqual((3, [2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
rearrange_channel_mux_table(to_channel_table(2, 1)))
self.assertTupleEqual((8, [3, 7, 2, 3, 7, 2, 3, 7, 0, 0, 0, 0]),
rearrange_channel_mux_table(to_channel_table(7, 3, 2)))
def test_many_channel(self):
self.assertEqual([0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
rearrange_channel_mux_table(to_channel_table(1, 0)))
self.assertTupleEqual((2, [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
rearrange_channel_mux_table(to_channel_table(1, 0)))
self.assertEqual([2, 5, 2, 5, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
rearrange_channel_mux_table(to_channel_table(2, 5)))
self.assertTupleEqual((6, [2, 5, 2, 5, 2, 5, 0, 0, 0, 0, 0, 0]),
rearrange_channel_mux_table(to_channel_table(2, 5)))
self.assertEqual([1, 3, 5, 1, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
rearrange_channel_mux_table(to_channel_table(1, 3, 5)))
self.assertTupleEqual((6, [1, 3, 5, 1, 3, 5, 0, 0, 0, 0, 0, 0]),
rearrange_channel_mux_table(to_channel_table(1, 3, 5)))
self.assertEqual([4, 5, 1, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
rearrange_channel_mux_table(to_channel_table(4, 1, 3, 5)))
self.assertTupleEqual((6, [4, 5, 1, 3, 4, 5, 0, 0, 0, 0, 0, 0]),
rearrange_channel_mux_table(to_channel_table(4, 1, 3, 5)))
self.assertEqual([5, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
rearrange_channel_mux_table(to_channel_table(4, 1, 2, 3, 5)))
self.assertEqual([6, 7, 8, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, ],
rearrange_channel_mux_table(to_channel_table(3, 4, 5, 6, 7, 8)))
self.assertTupleEqual((6, [5, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0]),
rearrange_channel_mux_table(to_channel_table(4, 1, 2, 3, 5)))
self.assertTupleEqual((9, [6, 7, 8, 3, 4, 5, 6, 7, 8, 0, 0, 0]),
rearrange_channel_mux_table(to_channel_table(3, 4, 5, 6, 7, 8)))
def test_count_channel(self):
self.assertEqual(count_channel(to_channel_table(7, 3, 2)), count_channel_without_re(to_channel_table(7, 3, 2)))
self.assertEqual(count_channel(to_channel_table(0, 10, 2)), count_channel_without_re(to_channel_table(0, 10, 2)))
self.assertEqual(expect_channel_count(), channel_count())
self.assertEqual(expect_channel_count(0), channel_count(0))
self.assertEqual(expect_channel_count(4), channel_count(4))
self.assertEqual(expect_channel_count(2, 4), channel_count(4, 2))
self.assertEqual(expect_channel_count(7, 3, 2), channel_count(7, 3, 2))
self.assertEqual(expect_channel_count(0, 1, 2), channel_count(0, 1, 2))
if __name__ == '__main__':
@@ -1,3 +0,0 @@
eclipse.preferences.version=1
inEditor=false
onBuild=false
@@ -1,2 +0,0 @@
eclipse.preferences.version=1
org.eclipse.cdt.debug.core.toggleBreakpointModel=com.ti.ccstudio.debug.CCSBreakpointMarker
@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<configurations XML_version="1.2" id="configurations_0">
<configuration XML_version="1.2" id="configuration_0">
<instance XML_version="1.2" desc="Texas Instruments XDS100v3 USB Debug Probe" href="connections/TIXDS100v3_Dot7_Connection.xml" id="Texas Instruments XDS100v3 USB Debug Probe" xml="TIXDS100v3_Dot7_Connection.xml" xmlpath="connections"/>
<connection XML_version="1.2" id="Texas Instruments XDS100v3 USB Debug Probe">
<instance XML_version="1.2" href="drivers/tixds100v2icepick_c.xml" id="drivers" xml="tixds100v2icepick_c.xml" xmlpath="drivers"/>
<instance XML_version="1.2" href="drivers/tixds100v2cs_dap.xml" id="drivers" xml="tixds100v2cs_dap.xml" xmlpath="drivers"/>
<instance XML_version="1.2" href="drivers/tixds100v2cortexM.xml" id="drivers" xml="tixds100v2cortexM.xml" xmlpath="drivers"/>
<property Type="choicelist" Value="2" id="The Converter Usage">
<choice Name="Generate 1149.7 2-pin advanced modes" value="enable">
<property Type="choicelist" Value="1" id="The Converter 1149.7 Frequency">
<choice Name="Overclock with user specified value" value="unused">
<property Type="choicelist" Value="5" id="-- Choose a value from 1.0MHz to 50.0MHz"/>
</choice>
</property>
<property Type="choicelist" Value="5" id="The Target Scan Format"/>
</choice>
</property>
<platform XML_version="1.2" id="platform_0">
<instance XML_version="1.2" desc="CC2640F128" href="devices/cc2640f128.xml" id="CC2640F128" xml="cc2640f128.xml" xmlpath="devices"/>
</platform>
</connection>
</configuration>
</configurations>
@@ -1,9 +0,0 @@
The 'targetConfigs' folder contains target-configuration (.ccxml) files, automatically generated based
on the device and connection settings specified in your project on the Properties > General page.
Please note that in automatic target-configuration management, changes to the project's device and/or
connection settings will either modify an existing or generate a new target-configuration file. Thus,
if you manually edit these auto-generated files, you may need to re-apply your changes. Alternatively,
you may create your own target-configuration file for this project and manage it manually. You can
always switch back to automatic target-configuration management by checking the "Manage the project's
target-configuration automatically" checkbox on the project's Properties > General page.
@@ -1,3 +0,0 @@
eclipse.preferences.version=1
inEditor=false
onBuild=false
@@ -1,2 +0,0 @@
eclipse.preferences.version=1
org.eclipse.cdt.debug.core.toggleBreakpointModel=com.ti.ccstudio.debug.CCSBreakpointMarker
@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<configurations XML_version="1.2" id="configurations_0">
<configuration XML_version="1.2" id="configuration_0">
<instance XML_version="1.2" desc="Texas Instruments XDS100v3 USB Debug Probe" href="connections/TIXDS100v3_Dot7_Connection.xml" id="Texas Instruments XDS100v3 USB Debug Probe" xml="TIXDS100v3_Dot7_Connection.xml" xmlpath="connections"/>
<connection XML_version="1.2" id="Texas Instruments XDS100v3 USB Debug Probe">
<instance XML_version="1.2" href="drivers/tixds100v2icepick_c.xml" id="drivers" xml="tixds100v2icepick_c.xml" xmlpath="drivers"/>
<instance XML_version="1.2" href="drivers/tixds100v2cs_dap.xml" id="drivers" xml="tixds100v2cs_dap.xml" xmlpath="drivers"/>
<instance XML_version="1.2" href="drivers/tixds100v2cortexM.xml" id="drivers" xml="tixds100v2cortexM.xml" xmlpath="drivers"/>
<property Type="choicelist" Value="2" id="The Converter Usage">
<choice Name="Generate 1149.7 2-pin advanced modes" value="enable">
<property Type="choicelist" Value="1" id="The Converter 1149.7 Frequency">
<choice Name="Overclock with user specified value" value="unused">
<property Type="choicelist" Value="5" id="-- Choose a value from 1.0MHz to 50.0MHz"/>
</choice>
</property>
<property Type="choicelist" Value="5" id="The Target Scan Format"/>
</choice>
</property>
<platform XML_version="1.2" id="platform_0">
<instance XML_version="1.2" desc="CC2640F128" href="devices/cc2640f128.xml" id="CC2640F128" xml="cc2640f128.xml" xmlpath="devices"/>
</platform>
</connection>
</configuration>
</configurations>
@@ -1,9 +0,0 @@
The 'targetConfigs' folder contains target-configuration (.ccxml) files, automatically generated based
on the device and connection settings specified in your project on the Properties > General page.
Please note that in automatic target-configuration management, changes to the project's device and/or
connection settings will either modify an existing or generate a new target-configuration file. Thus,
if you manually edit these auto-generated files, you may need to re-apply your changes. Alternatively,
you may create your own target-configuration file for this project and manage it manually. You can
always switch back to automatic target-configuration management by checking the "Manage the project's
target-configuration automatically" checkbox on the project's Properties > General page.
@@ -9,6 +9,6 @@
<linkerCommandFile value="cc26x0f128.cmd"/>
<rts value="libc.a"/>
<createSlaveProjects value=""/>
<connection value="common/targetdb/connections/TIXDS110_Connection.xml"/>
<isTargetManual value="true"/>
<connection value="common/targetdb/connections/TIXDS100v3_Dot7_Connection.xml"/>
<isTargetManual value="false"/>
</projectOptions>
@@ -9,6 +9,6 @@
<linkerCommandFile value="cc26x0f128.cmd"/>
<rts value="libc.a"/>
<createSlaveProjects value=""/>
<connection value="common/targetdb/connections/TIXDS110_Connection.xml"/>
<isTargetManual value="true"/>
<connection value="common/targetdb/connections/TIXDS100v3_Dot7_Connection.xml"/>
<isTargetManual value="false"/>
</projectOptions>
@@ -9,6 +9,6 @@
<linkerCommandFile value="cc26x0f128.cmd"/>
<rts value="libc.a"/>
<createSlaveProjects value=""/>
<connection value="common/targetdb/connections/TIXDS100v3_Dot7_Connection.xml"/>
<connection value="common/targetdb/connections/TIXDS110_Connection.xml"/>
<isTargetManual value="false"/>
</projectOptions>
@@ -72,7 +72,6 @@
</option>
<option id="com.ti.ccstudio.buildDefinitions.TMS470_18.1.compilerID.DEFINE.45713043" name="Pre-define NAME (--define, -D)" superClass="com.ti.ccstudio.buildDefinitions.TMS470_18.1.compilerID.DEFINE" valueType="definedSymbols">
<listOptionValue builtIn="false" value="BOARD_DISPLAY_EXCLUDE_UART"/>
<listOptionValue builtIn="false" value="HEADSTAGE_NOTIFY_USE_ATT"/>
<listOptionValue builtIn="false" value="POWER_SAVING"/>
<listOptionValue builtIn="false" value="BOOSTXL_CC2650MA"/>
<listOptionValue builtIn="false" value="HEADSTAGE_MA_USE_SPI2"/>
@@ -1,19 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<configurations XML_version="1.2" id="configurations_0">
<configuration XML_version="1.2" id="Texas Instruments XDS100v3 USB Debug Probe_0">
<instance XML_version="1.2" desc="Texas Instruments XDS100v3 USB Debug Probe_0" href="connections/TIXDS100v3_Dot7_Connection.xml" id="Texas Instruments XDS100v3 USB Debug Probe_0" xml="TIXDS100v3_Dot7_Connection.xml" xmlpath="connections"/>
<connection XML_version="1.2" id="Texas Instruments XDS100v3 USB Debug Probe_0">
<instance XML_version="1.2" href="drivers/tixds100v2icepick_c.xml" id="drivers" xml="tixds100v2icepick_c.xml" xmlpath="drivers"/>
<instance XML_version="1.2" href="drivers/tixds100v2cs_dap.xml" id="drivers" xml="tixds100v2cs_dap.xml" xmlpath="drivers"/>
<instance XML_version="1.2" href="drivers/tixds100v2cortexM.xml" id="drivers" xml="tixds100v2cortexM.xml" xmlpath="drivers"/>
<property Type="choicelist" Value="2" id="The Converter Usage">
<choice Name="Generate 1149.7 2-pin advanced modes" value="enable">
<property Type="choicelist" Value="1" id="The Converter 1149.7 Frequency">
<choice Name="Overclock with user specified value" value="unused">
<property Type="choicelist" Value="5" id="-- Choose a value from 1.0MHz to 50.0MHz"/>
</choice>
</property>
<property Type="choicelist" Value="5" id="The Target Scan Format"/>
<configuration XML_version="1.2" id="Texas Instruments XDS110 USB Debug Probe_0">
<instance XML_version="1.2" desc="Texas Instruments XDS110 USB Debug Probe_0" href="connections/TIXDS110_Connection.xml" id="Texas Instruments XDS110 USB Debug Probe_0" xml="TIXDS110_Connection.xml" xmlpath="connections"/>
<connection XML_version="1.2" id="Texas Instruments XDS110 USB Debug Probe_0">
<instance XML_version="1.2" href="drivers/tixds510icepick_c.xml" id="drivers" xml="tixds510icepick_c.xml" xmlpath="drivers"/>
<instance XML_version="1.2" href="drivers/tixds510cs_dap.xml" id="drivers" xml="tixds510cs_dap.xml" xmlpath="drivers"/>
<instance XML_version="1.2" href="drivers/tixds510cortexM.xml" id="drivers" xml="tixds510cortexM.xml" xmlpath="drivers"/>
<property Type="choicelist" Value="1" id="Power Selection">
<choice Name="Probe supplied power" value="1">
<property Type="stringfield" Value="3.3" id="Voltage Level"/>
</choice>
</property>
<property Type="choicelist" Value="0" id="JTAG Signal Isolation"/>
<property Type="choicelist" Value="4" id="SWD Mode Settings">
<choice Name="cJTAG (1149.7) 2-pin advanced modes" value="enable">
<property Type="choicelist" Value="1" id="XDS110 Aux Port"/>
</choice>
</property>
<platform XML_version="1.2" id="platform_0">
@@ -9,6 +9,6 @@
<linkerCommandFile value="cc26x0f128.cmd"/>
<rts value="libc.a"/>
<createSlaveProjects value=""/>
<connection value="common/targetdb/connections/TIXDS100v3_Dot7_Connection.xml"/>
<connection value="common/targetdb/connections/TIXDS110_Connection.xml"/>
<isTargetManual value="false"/>
</projectOptions>
@@ -12,6 +12,7 @@
<stringAttribute key="com.ti.ccstudio.debug.debugModel.ATTR_TARGET_CONFIG" value="${target_config_active_default:simple_peripheral_cc2650em_stack}"/>
<stringAttribute key="com.ti.ccstudio.debug.debugModel.MRU_PROGRAM.C:\ti\simplelink\ble_sdk_2_02_02_25\examples\cc2650em\simple_peripheral\ccs\stack\targetConfigs\CC2650F128.ccxml.Texas Instruments XDS100v3 USB Debug Probe_0/Cortex_M3_0" value="C:/ti\simplelink\ble_sdk_2_02_02_25\examples\cc2650em\simple_peripheral\ccs\stack\FlashROM\simple_peripheral_cc2650em_stack.out"/>
<stringAttribute key="com.ti.ccstudio.debug.debugModel.MRU_PROGRAM.C:\ti\simplelink\ble_sdk_2_02_02_25\examples\cc2650em\simple_peripheral\ccs\stack\targetConfigs\CC2650F128.ccxml.Texas Instruments XDS110 USB Debug Probe/Cortex_M3_0" value="C:/ti\simplelink\ble_sdk_2_02_02_25\examples\cc2650em\simple_peripheral\ccs\stack\FlashROM\simple_peripheral_cc2650em_stack.out"/>
<stringAttribute key="com.ti.ccstudio.debug.debugModel.MRU_PROGRAM.C:\ti\simplelink\ble_sdk_2_02_02_25\examples\cc2650em\simple_peripheral\ccs\stack\targetConfigs\CC2650F128.ccxml.Texas Instruments XDS110 USB Debug Probe_0/Cortex_M3_0" value="C:/ti\simplelink\ble_sdk_2_02_02_25\examples\cc2650em\simple_peripheral\ccs\stack\FlashROM\simple_peripheral_cc2650em_stack.out"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/simple_peripheral_cc2650em_stack"/>
</listAttribute>
@@ -1,19 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<configurations XML_version="1.2" id="configurations_0">
<configuration XML_version="1.2" id="Texas Instruments XDS100v3 USB Debug Probe_0">
<instance XML_version="1.2" desc="Texas Instruments XDS100v3 USB Debug Probe_0" href="connections/TIXDS100v3_Dot7_Connection.xml" id="Texas Instruments XDS100v3 USB Debug Probe_0" xml="TIXDS100v3_Dot7_Connection.xml" xmlpath="connections"/>
<connection XML_version="1.2" id="Texas Instruments XDS100v3 USB Debug Probe_0">
<instance XML_version="1.2" href="drivers/tixds100v2icepick_c.xml" id="drivers" xml="tixds100v2icepick_c.xml" xmlpath="drivers"/>
<instance XML_version="1.2" href="drivers/tixds100v2cs_dap.xml" id="drivers" xml="tixds100v2cs_dap.xml" xmlpath="drivers"/>
<instance XML_version="1.2" href="drivers/tixds100v2cortexM.xml" id="drivers" xml="tixds100v2cortexM.xml" xmlpath="drivers"/>
<property Type="choicelist" Value="2" id="The Converter Usage">
<choice Name="Generate 1149.7 2-pin advanced modes" value="enable">
<property Type="choicelist" Value="1" id="The Converter 1149.7 Frequency">
<choice Name="Overclock with user specified value" value="unused">
<property Type="choicelist" Value="5" id="-- Choose a value from 1.0MHz to 50.0MHz"/>
</choice>
</property>
<property Type="choicelist" Value="5" id="The Target Scan Format"/>
<configuration XML_version="1.2" id="Texas Instruments XDS110 USB Debug Probe_0">
<instance XML_version="1.2" desc="Texas Instruments XDS110 USB Debug Probe_0" href="connections/TIXDS110_Connection.xml" id="Texas Instruments XDS110 USB Debug Probe_0" xml="TIXDS110_Connection.xml" xmlpath="connections"/>
<connection XML_version="1.2" id="Texas Instruments XDS110 USB Debug Probe_0">
<instance XML_version="1.2" href="drivers/tixds510icepick_c.xml" id="drivers" xml="tixds510icepick_c.xml" xmlpath="drivers"/>
<instance XML_version="1.2" href="drivers/tixds510cs_dap.xml" id="drivers" xml="tixds510cs_dap.xml" xmlpath="drivers"/>
<instance XML_version="1.2" href="drivers/tixds510cortexM.xml" id="drivers" xml="tixds510cortexM.xml" xmlpath="drivers"/>
<property Type="choicelist" Value="1" id="Power Selection">
<choice Name="Probe supplied power" value="1">
<property Type="stringfield" Value="3.3" id="Voltage Level"/>
</choice>
</property>
<property Type="choicelist" Value="0" id="JTAG Signal Isolation"/>
<property Type="choicelist" Value="4" id="SWD Mode Settings">
<choice Name="cJTAG (1149.7) 2-pin advanced modes" value="enable">
<property Type="choicelist" Value="1" id="XDS110 Aux Port"/>
</choice>
</property>
<platform XML_version="1.2" id="platform_0">
@@ -219,53 +219,64 @@ SPICC26XXDMA_Object spiCC26XXDMAObjects[BOOSTXL_CC2650MA_SPICOUNT];
/* SPI configuration structure, describing which pins are to be used */
const SPICC26XXDMA_HWAttrsV1 spiCC26XXDMAHWAttrs[BOOSTXL_CC2650MA_SPICOUNT] = {
//
{
.baseAddr = SSI0_BASE,
.intNum = INT_SSI0_COMB,
.intPriority = ~0,
.swiPriority = 0,
.powerMngrId = PowerCC26XX_PERIPH_SSI0,
.defaultTxBufValue = 0,
.rxChannelBitMask = 1<<UDMA_CHAN_SSI0_RX,
.txChannelBitMask = 1<<UDMA_CHAN_SSI0_TX,
.mosiPin = Board_SPI0_MOSI,
.misoPin = Board_SPI0_MISO,
.clkPin = Board_SPI0_CLK,
.csnPin = Board_SPI0_CS
//
.baseAddr = SSI0_BASE,
.intNum = INT_SSI0_COMB,
.intPriority = ~0,
.swiPriority = 0,
.powerMngrId = PowerCC26XX_PERIPH_SSI0,
.defaultTxBufValue = 0,
.rxChannelBitMask = 1 << UDMA_CHAN_SSI0_RX,
.txChannelBitMask = 1 << UDMA_CHAN_SSI0_TX,
.mosiPin = Board_SPI0_MOSI,
.misoPin = Board_SPI0_MISO,
.clkPin = Board_SPI0_CLK,
.csnPin = Board_SPI0_CS
//
},
#ifdef HEADSTAGE_MA_USE_SPI2
{
.baseAddr = SSI1_BASE,
.intNum = INT_SSI1_COMB,
.intPriority = ~0,
.swiPriority = 0,
.powerMngrId = PowerCC26XX_PERIPH_SSI1,
.defaultTxBufValue = 0,
.rxChannelBitMask = 1<<UDMA_CHAN_SSI1_RX,
.txChannelBitMask = 1<<UDMA_CHAN_SSI1_TX,
.mosiPin = Board_SPI1_MOSI,
.misoPin = Board_SPI1_MISO,
.clkPin = Board_SPI1_CLK,
.csnPin = Board_SPI1_CS
//
.baseAddr = SSI1_BASE,
.intNum = INT_SSI1_COMB,
.intPriority = ~0,
.swiPriority = 0,
.powerMngrId = PowerCC26XX_PERIPH_SSI1,
.defaultTxBufValue = 0,
.rxChannelBitMask = 1 << UDMA_CHAN_SSI1_RX,
.txChannelBitMask = 1 << UDMA_CHAN_SSI1_TX,
.mosiPin = Board_SPI1_MOSI,
.misoPin = Board_SPI1_MISO,
.clkPin = Board_SPI1_CLK,
.csnPin = Board_SPI1_CS //
},
#endif
};
/* SPI configuration structure */
const SPI_Config SPI_config[] = {
const SPI_Config SPI_config[] = { //
{
.fxnTablePtr = &SPICC26XXDMA_fxnTable,
.object = &spiCC26XXDMAObjects[0],
.hwAttrs = &spiCC26XXDMAHWAttrs[0]
//
.fxnTablePtr = &SPICC26XXDMA_fxnTable,
.object = &spiCC26XXDMAObjects[0],
.hwAttrs = &spiCC26XXDMAHWAttrs[0]
//
},
#ifdef HEADSTAGE_MA_USE_SPI2
{
.fxnTablePtr = &SPICC26XXDMA_fxnTable,
.object = &spiCC26XXDMAObjects[1],
.hwAttrs = &spiCC26XXDMAHWAttrs[1]
//
.fxnTablePtr = &SPICC26XXDMA_fxnTable,
.object = &spiCC26XXDMAObjects[1],
.hwAttrs = &spiCC26XXDMAHWAttrs[1]
//
},
{NULL, NULL, NULL}
};
#endif
{NULL, NULL, NULL}};
/*
* ========================== SPI DMA end =====================================
*/
*/
/*
* ========================== Crypto begin ====================================
@@ -503,22 +514,165 @@ const PWM_Config PWM_config[BOOSTXL_CC2650MA_PWMCOUNT + 1] = {
*/
/*
* ============================= I2C Begin=====================================
*/
#ifdef ELITE_I2C
/* Generic I2C instance identifiers */
#define Board_I2C CC2650_MA_I2C0
/*!
* @def CC2650_LAUNCHXL_I2CName
* @brief Enum of I2C names on the CC2650 dev board
* ============================= ADC begin ======================================
*/
typedef enum CC2650_MA_I2CName {
CC2650_MA_I2C0 = 0,
CC2650_MA_I2CCOUNT
} CC2650_MA_I2CName;
#ifdef HEADSTAGE_MA_USE_ADC
#include <ti/drivers/ADC.h>
#include <ti/drivers/adc/ADCCC26XX.h>
#if defined(__TI_COMPILER_VERSION__)
#pragma DATA_SECTION(ADC_config, ".const:ADC_config")
#pragma DATA_SECTION(adcCC26xxHWAttrs, ".const:adcCC26xxHWAttrs")
#endif
ADCCC26XX_Object adcCC26xxObjects[BOOSTXL_CC2650MA_ADCCOUNT];
const ADCCC26XX_HWAttrs adcCC26xxHWAttrs[BOOSTXL_CC2650MA_ADCCOUNT] = {
//
{
//
.adcDIO = DIO7,
.adcCompBInput = ADC_COMPB_IN_AUXIO7,
.refSource = ADCCC26XX_FIXED_REFERENCE,
.samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
.inputScalingEnabled = true,
.triggerSource = ADCCC26XX_TRIGGER_MANUAL
//
},
{
//
.adcDIO = DIO8,
.adcCompBInput = ADC_COMPB_IN_AUXIO6,
.refSource = ADCCC26XX_FIXED_REFERENCE,
.samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
.inputScalingEnabled = true,
.triggerSource = ADCCC26XX_TRIGGER_MANUAL
//
},
{
//
.adcDIO = DIO9,
.adcCompBInput = ADC_COMPB_IN_AUXIO5,
.refSource = ADCCC26XX_FIXED_REFERENCE,
.samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
.inputScalingEnabled = true,
.triggerSource = ADCCC26XX_TRIGGER_MANUAL
//
},
{
//
.adcDIO = PIN_UNASSIGNED,
.adcCompBInput = ADC_COMPB_IN_AUXIO4,
.refSource = ADCCC26XX_FIXED_REFERENCE,
.samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
.inputScalingEnabled = true,
.triggerSource = ADCCC26XX_TRIGGER_MANUAL
//
},
{
//
.adcDIO = PIN_UNASSIGNED,
.adcCompBInput = ADC_COMPB_IN_AUXIO3,
.refSource = ADCCC26XX_FIXED_REFERENCE,
.samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
.inputScalingEnabled = true,
.triggerSource = ADCCC26XX_TRIGGER_MANUAL
//
},
{
//
.adcDIO = PIN_UNASSIGNED,
.adcCompBInput = ADC_COMPB_IN_AUXIO2,
.refSource = ADCCC26XX_FIXED_REFERENCE,
.samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
.inputScalingEnabled = true,
.triggerSource = ADCCC26XX_TRIGGER_MANUAL
//
},
{
//
.adcDIO = PIN_UNASSIGNED,
.adcCompBInput = ADC_COMPB_IN_AUXIO1,
.refSource = ADCCC26XX_FIXED_REFERENCE,
.samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
.inputScalingEnabled = true,
.triggerSource = ADCCC26XX_TRIGGER_MANUAL
//
},
{
//
.adcDIO = PIN_UNASSIGNED,
.adcCompBInput = ADC_COMPB_IN_AUXIO0,
.refSource = ADCCC26XX_FIXED_REFERENCE,
.samplingDuration = ADCCC26XX_SAMPLING_DURATION_10P9_MS,
.inputScalingEnabled = true,
.triggerSource = ADCCC26XX_TRIGGER_MANUAL
//
},
{
//
.adcDIO = PIN_UNASSIGNED,
.adcCompBInput = ADC_COMPB_IN_DCOUPL,
.refSource = ADCCC26XX_FIXED_REFERENCE,
.samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
.inputScalingEnabled = true,
.triggerSource = ADCCC26XX_TRIGGER_MANUAL
//
},
{
//
.adcDIO = PIN_UNASSIGNED,
.adcCompBInput = ADC_COMPB_IN_VSS,
.refSource = ADCCC26XX_FIXED_REFERENCE,
.samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
.inputScalingEnabled = true,
.triggerSource = ADCCC26XX_TRIGGER_MANUAL
//
},
{
//
.adcDIO = PIN_UNASSIGNED,
.adcCompBInput = ADC_COMPB_IN_VDDS,
.refSource = ADCCC26XX_FIXED_REFERENCE,
.samplingDuration = ADCCC26XX_SAMPLING_DURATION_2P7_US,
.inputScalingEnabled = true,
.triggerSource = ADCCC26XX_TRIGGER_MANUAL
//
}
//
};
const ADC_Config ADC_config[] = {
//
{&ADCCC26XX_fxnTable, &adcCC26xxObjects[0], &adcCC26xxHWAttrs[0]},
{&ADCCC26XX_fxnTable, &adcCC26xxObjects[1], &adcCC26xxHWAttrs[1]},
{&ADCCC26XX_fxnTable, &adcCC26xxObjects[2], &adcCC26xxHWAttrs[2]},
{&ADCCC26XX_fxnTable, &adcCC26xxObjects[3], &adcCC26xxHWAttrs[3]},
{&ADCCC26XX_fxnTable, &adcCC26xxObjects[4], &adcCC26xxHWAttrs[4]},
{&ADCCC26XX_fxnTable, &adcCC26xxObjects[5], &adcCC26xxHWAttrs[5]},
{&ADCCC26XX_fxnTable, &adcCC26xxObjects[6], &adcCC26xxHWAttrs[6]},
{&ADCCC26XX_fxnTable, &adcCC26xxObjects[7], &adcCC26xxHWAttrs[7]},
{&ADCCC26XX_fxnTable, &adcCC26xxObjects[8], &adcCC26xxHWAttrs[8]},
{&ADCCC26XX_fxnTable, &adcCC26xxObjects[9], &adcCC26xxHWAttrs[9]},
{&ADCCC26XX_fxnTable, &adcCC26xxObjects[10], &adcCC26xxHWAttrs[10]},
{NULL, NULL, NULL},
};
#endif // HEADSTAGE_MA_USE_ADC
/*
* ============================= ADC end ======================================
*/
/*
* ============================= I2C Begin=====================================
*/
#ifdef HEADSTAGE_LED_USE_I2C
#define Board_I2C0_SCL0 IOID_10
#define Board_I2C0_SDA0 IOID_11
/* Place into subsections to allow the TI linker to remove items properly */
#if defined(__TI_COMPILER_VERSION__)
@@ -530,10 +684,10 @@ typedef enum CC2650_MA_I2CName {
#include <ti/drivers/i2c/I2CCC26XX.h>
/* I2C objects */
I2CCC26XX_Object i2cCC26xxObjects[CC2650_MA_I2CCOUNT];
I2CCC26XX_Object i2cCC26xxObjects[BOOSTXL_CC2650MA_I2CCOUNT];
/* I2C configuration structure, describing which pins are to be used */
const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[CC2650_MA_I2CCOUNT] = {
const I2CCC26XX_HWAttrsV1 i2cCC26xxHWAttrs[BOOSTXL_CC2650MA_I2CCOUNT] = {
{
.baseAddr = I2C0_BASE,
.powerMngrId = PowerCC26XX_PERIPH_I2C0,
@@ -554,9 +708,11 @@ const I2C_Config I2C_config[] = {
},
{NULL, NULL, NULL}
};
#endif
/*
* ========================== I2C end =========================================
*/
/*
* ============================= Watchdog begin =====================================
*/
@@ -137,7 +137,7 @@ extern const PIN_Config BoardGpioInitTable[];
#define Board_PWMPIN4 PIN_UNASSIGNED
#define Board_PWMPIN5 PIN_UNASSIGNED
#define Board_PWMPIN6 PIN_UNASSIGNED
#define Board_PWMPIN7 PIN_UNASSIGNED
#define Board_PWMPIN7 IOID_11
/** ============================================================================
* Instance identifiers
@@ -100,7 +100,6 @@ if (typeof NO_ROM == 'undefined' || (typeof NO_ROM != 'undefined' && NO_ROM == 0
/* ================ Clock configuration ================ */
var Clock = xdc.useModule('ti.sysbios.knl.Clock');
var Timestamp = xdc.useModule('xdc.runtime.Timestamp');
/*
* When using Power and calibrateRCOSC is set to true, this should be set to 10.
* The timer used by the Clock module supports TickMode_DYNAMIC. This enables us
@@ -113,7 +112,6 @@ var Timestamp = xdc.useModule('xdc.runtime.Timestamp');
Clock.tickPeriod = 10;
Clock.swiPriority = 5;
Timestamp.SupportProxy = xdc.useModule('ti.sysbios.family.arm.cc26xx.TimestampProvider');
/* ================ Types configuration ================ */
var Types = xdc.useModule('xdc.runtime.Types');
@@ -368,9 +368,6 @@ static void HostTestApp_processAttEvent(gattMsgEvent_t *message) {
} else if (method == ATT_HANDLE_VALUE_NOTI) {
attHandleValueNoti_t *att_notify = (attHandleValueNoti_t *)(&message->msg);
master_handle_notify(att_notify->len, att_notify->pValue);
} else if (method == ATT_HANDLE_VALUE_IND) {
attHandleValueInd_t *att_indicate = (attHandleValueInd_t *)(&message->msg);
master_handle_notify(att_indicate->len, att_indicate->pValue);
}
// Free message. Needed only for ATT Protocol messages
@@ -1,28 +0,0 @@
@startuml
start
while (negedge chip select)
if (rxbuf is wrong) then (yes)
:modify data until it is correct;
else
:pass;
endif
partition headstage_notify_append_data {
if (buf offset == INIT) then (yes)
:reset timestamp;
endif
if (buf offset == BUFF_SIZE)
:set time delta;
endif
:append data & return index;
}
if (buf offset == BUFF_SIZE)
:headstage_notify_send(0.676ms);
endif
:headstage_spi_lsk_transaction (0.528ms);
endwhile
stop
@enduml
@@ -242,12 +242,13 @@ extern ICall_Semaphore semaphore;
* make task sleep in certain [ms].
* count with cpu tick.
*/
#define headstage_cpu_delay_ms(ms) CPUdelay(ms * 16000)
#define headstage_cpu_delay_ms(ms) CPUdelay((ms) * 16000)
/**
* make task sleep in certain [us].
* count with cpu tick.
*/
#define headstage_cpu_delay_us(us) CPUdelay(us * 16)
#define headstage_cpu_delay_us(us) CPUdelay((us) * 16)
/*======================================
==== abstract function declaration ====
@@ -282,10 +283,12 @@ static void headstage_update_vis_instruction(uint8_t vis_oper);
*/
static uint8_t CHIP_ID = 0;
#define CONNECT_HANDLE_UNCONNECTED 0xFFFF
/**
* connection handle. updated by system.
*/
static uint16_t CONNECT_HANDLE = 0;
static uint16_t CONNECT_HANDLE = CONNECT_HANDLE_UNCONNECTED;
/*====================
==== event table ====
@@ -311,7 +314,7 @@ typedef struct {
==== device implement implement header ====
=========================================*/
#include "headstage_zm.h"
#include "headstage_uni.h"
/*======================
==== main function ====
@@ -1,12 +1,11 @@
/* Copyright (c) 2019. BioPro. Scientific.
*/
#ifndef HEADSTAGE_LED_H
#error "headstage_led.h not included"
#endif
#ifndef HEADSTAGE_CIS_LED_H
#define HEADSTAGE_CIS_LED_H
#include "headstage_led.h"
// clang-format off
#define CIS_LED_DISABLE 0x00
#define CIS_LED_ENABLE 0x01
@@ -30,13 +30,15 @@ static void headstage_clock_callback(UArg arg) {
// XXX function not tested
// period in mini second
#define headstage_clock_open(_period) \
do { \
Clock_Params param; \
Clock_Params_init(&param); \
param.period = 48000*(_period); \
param.startFlag = false; \
clock_handle = Clock_create(headstage_clock_callback, 1, &param, NULL); \
#define headstage_clock_open(p) \
do { \
Clock_Params param; \
Clock_Params_init(&param); \
param.period = 0; \
param.startFlag = false; \
clock_handle = Clock_create(headstage_clock_callback, 0, &param, NULL); \
uint32_t _period = (p)*1000 / Clock_tickPeriod; \
Clock_setPeriod(clock_handle, _period); \
} while (0)
#define headstage_clock_set_frequency(frequency) \
@@ -1,84 +0,0 @@
/* Copyright (c) 2019. BioPro. Scientific.
*/
/*
Headstage indicate utility
==========================
reference code :
root:
glucose.c
glucserive.c
code need modifying:
headstage_indicate.h
simple_gatt_profile.c : WriteAtterCB -> add case "indication" to support indicate
sipmle_peripheral.c : find another service callback
use this website to construct software structure : http://plantuml.com/zh/
reference document:
bluetooth Core5.1 Vol 3, Part F, Section 3.4.6
The Prepare Write Request is used to request the server to prepare to write the
value of an attribute. The server will respond to this request with a Prepare Write
Response, so that the client can verify that the value was received correctly.
host-test can ask simple-peripheral to prepare the queue to write attribute
5.3.4.3 Queued Writes
Prepare Write commands allows a GATT server to send more payload data by queuing up multiple write
requests. The default queue size is 5. With a default MTU of 23 and payload of 18 bytes, up to 90 bytes of
payload can be sent. Refer to Core_v4.2 specification (Vol 3, Part F, Section 3.4.6) for more information
on queued writes.
Adjust the Prepare Write queue with GATTServApp_SetParameter with parameter
GATT_PARAM_NUM_PREPARE_WRITES. There is no specified limit, but it is bounded by the available
HEAPMGR space. Refer to the API definition in gattservapp.h.
GATT_PARAM_NUM_PREPARE_WRITES
*/
#ifndef HEADSTAGE_INDICATE_H
#define HEADSTAGE_INDICATE_H
#include <xdc/runtime/Timestamp.h>
#define headstage_time_stamp() Timestamp_get32()
/*==========================
==== indicate function ====
=========================*/
/*
* send indicate
* connHandle -> where to assign this parameter
*/
static bStatus_t headstage_indicate() {
uint16_t buffer_size = BLE_NOT_BUFF_SIZE;
uint8_t *value = (uint8_t *)GATT_bm_alloc(CONNECT_HANDLE, ATT_HANDLE_VALUE_IND, GATT_MAX_MTU,&buffer_size);
if (value != NULL) {
memcpy(value, headstage_notify_buffer, buffer_size);
}
attHandleValueInd_t indicate = {
// clang-format off
.handle = 0x1E,
.len = buffer_size,
.pValue = value
// clang-format on
};
if (GATT_Indication(CONNECT_HANDLE, &indicate, 0, ICall_getEntityId()) != SUCCESS) {
GATT_bm_free((gattMsg_t *)&indicate, ATT_HANDLE_VALUE_IND);
}
return TRUE;
}
#endif
@@ -125,7 +125,6 @@ static uint8_t headstage_led_set_color(uint16_t *ins_buf, uint8_t repeat, uint8_
/*============================
==== LED implement (SPI) ====
===========================*/
#define HEADSTAGE_LED_USE_SPI
#ifdef HEADSTAGE_LED_USE_SPI
@@ -192,33 +191,48 @@ static void headstage_led_color(uint8_t color) {
==== LED implement (GPIO) ====
============================*/
#ifdef BOOSTXL_CC2650MA
#define HEADSTAGE_LED_USE_GPIO
#endif
#ifdef HEADSTAGE_LED_USE_GPIO
#include "headstage_pin.h"
/*
every 400us to transmit spi data
*/
#define SPI_LED_BUFF_SIZE 20
#define SPI_LED_REPEAT 2
static uint16_t headstage_spi_led_txbuf[SPI_LED_BUFF_SIZE];
#define LED_GPIO_DELAY 16 * 400 // 2500hz
/**
* every 400us to transmit spi data
*/
static void headstage_led_spi_transmit() {
for (int8_t i = 0; i < 8; i++) {
uint16_t d = headstage_spi_led_txbuf[i];
for (int8_t j = 15; j >= 0; j--) {
int16_t v = (d & (1 << j)); // why check > 0 or not
bool SET_LED = (v > 0) ? 1 : 0;
bool high = ((d & (1 << j)) > 0) ? 1 : 0;
headstage_pin_output(PIN_LED_CLK, 1);
CPUdelay(16 * 400); // 2500hz
headstage_pin_output(PIN_LED_OUT, SET_LED);
CPUdelay(LED_GPIO_DELAY); // 2500hz
headstage_pin_output(PIN_LED_OUT, high);
headstage_pin_output(PIN_LED_CLK, 0);
CPUdelay(16 * 400); // 2500hz
CPUdelay(LED_GPIO_DELAY); // 2500hz
}
}
}
static void headstage_led_spi_color(uint8_t color) {
static void headstage_led_open() {}
static void headstage_led_close() {}
static void headstage_led_send(LEDParameter *led) {
headstage_led_set_buffer(headstage_spi_led_txbuf, SPI_LED_REPEAT, led);
headstage_led_spi_transmit();
}
static void headstage_led_color(uint8_t color) {
headstage_led_set_color(headstage_spi_led_txbuf, SPI_LED_REPEAT, color);
headstage_led_spi_transmit();
}
@@ -31,7 +31,8 @@ optional implement
#include <xdc/runtime/Timestamp.h>
#define headstage_time_stamp_us() (Timestamp_get32() / 2)
#define headstage_time_stamp() Timestamp_get32()
#define headstage_time_stamp_ms() (Timestamp_get32() / 32)
/*========================
==== notify function ====
@@ -51,7 +52,7 @@ static void headstage_notify_send() {
if (value != NULL) {
memcpy(value, headstage_notify_buffer, buffer_size);
attHandleValueNoti_t notify = {
attHandleValueNoti_t notify =
// clang-format off
.handle = 0x1E,
.len = buffer_size,
@@ -66,9 +67,24 @@ static void headstage_notify_send() {
}
#else
SimpleProfile_SetParameter(BLE_NOT_BUFF_CHAR, BLE_NOT_BUFF_SIZE, headstage_notify_buffer) ;
SimpleProfile_SetParameter(BLE_NOT_BUFF_CHAR, BLE_NOT_BUFF_SIZE, headstage_notify_buffer);
#endif
}
#if defined(HEADSTAGE_TNI_H)
#include "tni/headstage_notify.h"
#elif defined(HEADSTAGE_UNI_H)
#include "tni/headstage_notify.h"
#elif defined(HEADSTAGE_ZM_H)
#include "zm/headstage_notify.h"
#elif defined(HEADSTAGE_STI_H)
#include "sti/headstage_notify.h"
#else
#error "headstage_notify"
#endif
#endif // HEADSTAGE_NOTIFY_H
@@ -0,0 +1,30 @@
/* Copyright (c) 2019. BioPro. Scientific.
*/
#ifndef HEADSTAGE_NOTIFY_GENERAL_H
#define HEADSTAGE_NOTIFY_GENERAL_H
#ifndef HEADSTAGE_NOTIFY_H
#error "headstage/headstage_notify.h not included"
#endif
static uint32_t not_buf_offset = 0;
static uint32_t not_time_stamp = 0;
static void headstage_notify_set_timestamp() {
not_time_stamp = headstage_time_stamp();
headstage_notify_buffer[2] = not_time_stamp & 0xFF;
headstage_notify_buffer[3] = (not_time_stamp >> 8) & 0xFF;
headstage_notify_buffer[4] = (not_time_stamp >> 16) & 0xFF;
headstage_notify_buffer[5] = (not_time_stamp >> 24) & 0xFF;
}
static void _headstage_notify_flip_buffer(uint8_t data_length) {
headstage_notify_buffer[0] = CHIP_ID;
headstage_notify_buffer[1] = data_length;
not_buf_offset = 0;
}
#endif // HEADSTAGE_NOTIFY_GENERAL_H
@@ -36,7 +36,6 @@ Real instruction format
#include "headstage_gptimer.h"
#include "headstage_notify.h"
#include "headstage_pin.h"
#include "tni/headstage_notify.h"
#include "tni/headstage_spi.h"
/*=================================
@@ -7,6 +7,16 @@
#ifndef HEADSTAGE_UNI_H
#define HEADSTAGE_UNI_H
/*============================
==== product information ====
===========================*/
#define DEVICE_NAME "Neulive-v0.3"
#define MAJOR_PRODUCT_NUMBER 1
#define MINOR_PRODUCT_NUMBER 1
#define MAJOR_VERSION_NUMBER 0
#define MINOR_VERSION_NUMBER 2
// TODO low frequency mode
// TODO battery record
// TODO watchdog function need implementing
@@ -15,6 +25,15 @@
/*=================
==== constant ====
=================*/
// data rate
// clang-format off
#define UMC_LSK_FREQ 5000 // 500 khz
#define UMC_ASK_FREQ 1000 // 100 khz
#define UMC_SYS_CLK 100000 // target is 8Mhz
#define UMC_POLY_R_CLK 1000 // poly-R switching clock
// clang-format on
// data transmit format 9'b PREAMBLE + 4'b HEADER + 10'bit DATA
// clang-format off
#define UMC_PREAMBLE 0b011000001
@@ -25,20 +44,18 @@
/*================
==== include ====
================*/
#include "time.h"
#include "population.h"
#include "headstage_arm.h"
#include "headstage_notify.h"
#include "headstage_debug.h"
#include "headstage_pin.h"
#include "headstage_led.h"
#include "headstage_arm.h"
#include "headstage_watchdog.h"
#include "headstage_notify.h"
#include "tni/headstage_notify.h"
#include "uni/headstage_spi.h"
#include "uni/headstage_pwm.h"
#include "uni/headstage_adc.h"
#include "uni/uni1.2_parameter.h"
#include "headstage_indicate.h"
/*===================================
==== instruction building macro ====
@@ -107,22 +124,16 @@
==== constant ====
=================*/
// data rate
// clang-format off
#define UMC_LSK_FREQ 100000 // 500 khz
#define UMC_ASK_FREQ 20000 // 100 khz
#define UMC_SYS_CLK 2000000 // target is 8Mhz
#define UMC_POLY_R_CLK 1000 // poly-R switching clock
// Neulive instruction macro
// UNI 1.2 instruction macro
#define UMC_HAND_SHAKE_SEND 0b0011000011
#define UMC_HAND_SHAKE_RECV 0b01010011000110000000110001100000
#define UMC_MODE_LSK_OUT 0b101001
#define UMC_CALIB_DONE 0b1010 // UMC_CALIB_DONE + UMC_MODE_LSK_OUT -> leave initial state and set "CHIP ID"
#define UMC_CONFIG_DONE 0b0100 // UMC_CONFIG_DONE + 6'bxxxxxx -> EXIT config state
#define UMC_CONFIG_DONE 0b0100 // UMC_CONFIG_DONE + 6'bxxxxxx -> EXIT config state
#define UMC_IRQ 0b1110
#define UMC_IRQ_CODE 0b001001 // UMC_IRQ + UMC_IRQ_CODE + CHIP ID -> when we want to go back to configure data.
#define UMC_IRQ_CODE 0b001001 // UMC_IRQ + UMC_IRQ_CODE + CHIP ID -> when we want to go back to configure data.
#define UMC_GOLDEN_KEY 0b01011010010110000010100101100000 //this is important to leave wait trigger state.
// we need to check transfer data meets or not
@@ -134,9 +145,10 @@
#define RIS_DEFAULT 0x00
#define RIS_SET_PARA 0x20
#define RIS_RECONFIG 0x40
#define RIS_RESET_AMP 0x60
#define RIS_DIR 0xA0
#define RIS_UMC_TRIG 0xC0
#define RIS_STI 0xF0
#define STI_MODE_DISABLE 0
#define STI_MODE_POS 1
@@ -179,7 +191,8 @@
#define REC_CHANNEL_COUNT 16
static uint16_t sti_waveform_table[5] = {
static uint16_t sti_waveform_table[6] = {
{0b000000},
{0b000011}, // positive
{0b001100}, // negative
{0b110000}, // p 2 s
@@ -191,9 +204,9 @@ static uint16_t sti_waveform_table[5] = {
// TODO when we choose trigger mode , but we can't transmit any trigger instruction.
static uint16_t sti_mode_table[4] = {
{0b001100}, // disable stimulation, it would there will be no trigger to be set
{0b110000}, // continuous mode
{0b001100}, // trigger mode
{0b000011}, // limited mode
{0b110000} // continuous mode
{0b000011} // limited mode
};
static uint16_t amp_band_table[8] = { //
@@ -210,6 +223,97 @@ static uint16_t fast_settle_table[2] = { //
{0b000000},
{0b000001}};
// XXX not used
static uint16_t sti_channel_table[4] = {
{0b000010}, // 3
{0b001000}, // 4
{0b001100}, // 5
{0b010000} // 6
};
/*
* we need to use this parameter
*/
#ifdef UNI_1P2
static uint16_t reverse_channel[16] = {{0x0A}, // 1
{0x0B},
{0x00},
{0x01},
{0x02},
{0x07},
{0x06},
{0x03},
{0x05},
{0x04},
{0x08},
{0xff},
{0x0c},
{0x09},
{0xff},
{0xff}};
#else
static uint16_t reverse_channel[16] = {{0x0A}, // 1
{0x00},
{0x01},
{0x02},
{0x03},
{0x08},
{0x07},
{0x06},
{0x05},
{0x04},
{0x09},
{0x0B},
{0xFF},
{0xFF},
{0xff},
{0xff}};
#endif
/* we can change amp channel from one to eight
* the user will choose these channel from this table
*/
#ifdef UNI_1p2
static uint16_t amp_channel_table[13] = { //
{0x03},
{0x04},
{0x05},
{0x08},
{0x0A},
{0x09},
{0x07},
{0x06},
{0x0B},
{0x0E},
{0x01},
{0x02},
{0x0D}};
#else
static uint16_t amp_channel_table[12] = { //
{0x02},
{0x03},
{0x04},
{0x05},
{0x0A},
{0x09},
{0x08},
{0x07},
{0x06},
{0x0b},
{0x01},
{0x0C}};
#endif
static uint16_t amp_gain_table[] = {
0b100011, // 2
0b101100, // 5
0b101001, // 10
0b000011, // 200
0b001100, // 500
0b001001, // 1000
};
/**
* pulse width, with unit us
*/
@@ -451,7 +555,6 @@ static void headstage_umc_state_transfer_lsk();
// clang-format off
#define EVT_UMC_ASK 0x0001
#define EVT_UMC_LSK 0x0002
#define EVT_UMC_STI 0x0004
// clang-format on
static void headstage_uni_event() {
@@ -465,12 +568,6 @@ static void headstage_uni_event() {
headstage_umc_state_transfer_lsk();
}
if (flag_mask(EVT_UMC_STI)) {
flag_disable(EVT_UMC_STI);
headstage_state = UMC_STATE_WAIT_TRIGGER;
headstage_umc_state_transfer_lsk();
}
if (EVENT_MASK == 0) {
// fast return
}
@@ -514,15 +611,17 @@ static void headstage_init() {
headstage_pin_open();
headstage_spi_open();
headstage_pwm_open();
headstage_led_spi_color(COLOR_GREEN);
// headstage_i2c_open();
// headstage_watchdog_open();
// if(headstage_watchdog_handle == NULL)
// {
// headstage_led_spi_color(COLOR_RED);
// headstage_led_color(COLOR_RED);
// }
headstage_pin_output(PIN_RESET, 1); // initialize DBS chip
headstage_pin_output(PIN_STI_SEL, 1); // chip select is ok
headstage_pin_output(PIN_STI_SEL, 0); // chip select is ok
headstage_pin_output(PIN_VGRP, 1); //
headstage_pin_output(PIN_FASTSET, 0); //
}
@@ -533,7 +632,7 @@ static void headstage_update_ris_instruction(uint8_t ins_len, uint8_t* instructi
uint8_t amp_lbf = (instruction[0] & 0b00000111);
uint8_t chopper = (instruction[1] & 0b00100000) >> 5;
uint8_t fast_settle = (instruction[1] & 0b00010000) >> 4;
uint8_t sti_waveform = (instruction[1] & 0b00001110) >> 1; // define pos to neg or neg to pos
uint8_t sti_waveform = (instruction[1] & 0b00001110) >> 1;
uint8_t sti_volt_h = (instruction[1] & 0b00000001);
uint8_t sti_volt_l = (instruction[2] & 0b11110000) >> 4;
uint8_t sti_volt = (sti_volt_h << 4) | sti_volt_l;
@@ -547,8 +646,8 @@ static void headstage_update_ris_instruction(uint8_t ins_len, uint8_t* instructi
INSTRUCTION.chopper = chopper;
INSTRUCTION.fast_settle = fast_settle;
INSTRUCTION.sti_volt = sti_volt;
INSTRUCTION.sti_channel_pmos = sti_channel_table[sti_chp];
INSTRUCTION.sti_channel_nmos = sti_channel_table[sti_chn];
INSTRUCTION.sti_channel_pmos = sti_chp;
INSTRUCTION.sti_channel_nmos = sti_chn;
break;
}
case RIS_SET_PARA: {
@@ -578,18 +677,18 @@ static void headstage_update_ris_instruction(uint8_t ins_len, uint8_t* instructi
// todo: check multichannel selection is correct or not
case RIS_DEFAULT: {
INSTRUCTION.channel_table[amp_channel_table[0] - 1] = TRUE;
INSTRUCTION.amp_gain = 5; // x1000
INSTRUCTION.pulse_width = 0; // 40us
INSTRUCTION.sti_times = 0; // repeat stimulation x1
INSTRUCTION.mode = 1; // trigger mode
INSTRUCTION.sti_freq = 3; // 30hz
INSTRUCTION.sti_waveform = 1; // positive
INSTRUCTION.chopper = 0; // turn off chopper
INSTRUCTION.fast_settle = 0; // turn on fast settling
INSTRUCTION.sti_volt = 0; // 2Volt
INSTRUCTION.sti_channel_nmos = 0; // sti nch = ch2 means sti turn off
INSTRUCTION.sti_channel_pmos = 1; // sti pch = ch1 means sti turn off
INSTRUCTION.amp_low_band_freq = 0; // the maximum
INSTRUCTION.amp_gain = 5; // x1000
INSTRUCTION.pulse_width = 0; // 40us
INSTRUCTION.sti_times = 0; // repeat stimulation x1
INSTRUCTION.mode = 1; // trigger mode
INSTRUCTION.sti_freq = 3; // 30hz
INSTRUCTION.sti_waveform = 1; // positive
INSTRUCTION.chopper = 0; // turn off chopper
INSTRUCTION.fast_settle = 0; // turn on fast settling
INSTRUCTION.sti_volt = 0; // 2Volt
INSTRUCTION.sti_channel_nmos = 15; // sti nch = ch2 means sti turn off
INSTRUCTION.sti_channel_pmos = 0; // sti pch = ch1 means sti turn off
INSTRUCTION.amp_low_band_freq = 0; // the maximum
// this for-loop is used for setting the amplifier channel
// for (unsigned int i = 0; i < REC_CHANNEL_COUNT; i++) {
@@ -597,13 +696,13 @@ static void headstage_update_ris_instruction(uint8_t ins_len, uint8_t* instructi
// }
break;
}
case RIS_RECONFIG:
// state_oper = EVT_STATE_CHANGE_REV;
break;
case RIS_UMC_TRIG:
tx_put_u32(0, build_configure_instruction(UMC_TRIG, UMC_STIMULUS));
flag_notify(EVT_UMC_STI);
/*
load
*/
case RIS_STI:
// tx_put_u32(0, build_configure_instruction(0b1011, 0b000011));
// headstage_spi_ask_transaction(4);
break;
case RIS_RESET_AMP:
@@ -637,7 +736,7 @@ static void headstage_update_vis_instruction(uint8_t vis_oper) {
headstage_pwm_start(headstage_poly_r_pwm_handle);
UMC_STATE.config_type = CONFIG_AMP_MUX;
UMC_STATE.reset_flag = 0;
headstage_led_spi_color(COLOR_BLUE);
headstage_led_color(COLOR_BLUE);
flag_notify(EVT_UMC_LSK);
}
@@ -667,9 +766,6 @@ static void headstage_update_vis_instruction(uint8_t vis_oper) {
}
}
/*
* todo: need to define some procedure to detect this device status
*/
static uint8_t headstage_debug_instruction(uint8_t* ins_buf) {
return 0;
}
@@ -679,56 +775,56 @@ static uint8_t headstage_debug_instruction(uint8_t* ins_buf) {
=====================*/
static void headstage_uni_test_data_append_notify_buffer(uint8_t* dat_buf) {
uint8_t channel = 0;
dat_buf[0] = dat_buf[0];
dat_buf[1] = (dat_buf[1] + 1) & 0xfc;
headstage_notify_append_data(channel, dat_buf);
uint8_t channel = 0;
uint16_t data_value = (((uint16_t)dat_buf[0] & 0x0F) << 6) | ((dat_buf[1] & 0xFC) >> 2);
headstage_notify_append_data(channel, &data_value);
// always send notify no matter buffer full or not
headstage_notify_flip_buffer();
headstage_notify_send();
}
// implement this function to detect
static void headstage_uni_delay() {
for (uint16_t i = 0; i < 1023; i++)
;
}
// todo: check data length extension with this function -> this function should be
static void headstage_uni_umc_data_append_notify_buffer(uint8_t* dat_buf) {
// check LSK data preamble ( 0b01100_0001 ) 58(01011000) 2c(00101100)
// sometimes we lose the first bit , it means we only receive
// 0110_0000_1010_1xxx_xxxx_xxxX_XXXX_XXXX and
// 1100_0001_0101_xxxx_xxxx_xxXX_XXXX_XXXX
if (((spi_rxbuf[0] & 0xC1) != 0xC1) && (spi_rxbuf[0] != 0x00)) {
headstage_uni_delay();
headstage_led_spi_color(COLOR_CYAN);
} else {
if ((dat_buf[1] & 0x28) == 0x28) {
dat_buf[0] = (dat_buf[0] << 1) | ((dat_buf[1] >> 7) & 0x01);
dat_buf[1] = (dat_buf[1] << 1) | ((dat_buf[2] >> 7) & 0x01);
dat_buf[2] = (dat_buf[2] << 1) | ((dat_buf[3] >> 7) & 0x01);
}
uint8_t channel;
if ((INSTRUCTION.enable_channel_number == 1) || (dat_buf[0] == 0xc1)) {
channel = reverse_channel[INSTRUCTION.last_enable_channel];
} else {
uint8_t channel_pointer = (INSTRUCTION.channel_pointer + 1) % INSTRUCTION.last_enable_channel;
INSTRUCTION.channel_pointer = channel_pointer;
channel = reverse_channel[INSTRUCTION.channel_mux[channel_pointer]];
}
// uint16_t data_value = (uint16_t)(((dat_buf[1] & 0x0F) << 6) | ((dat_buf[2] & 0xFC) >> 2));
uint8_t data_size = headstage_notify_append_data(channel, dat_buf);
if (data_size >= BLE_NOT_BUFF_SIZE) {
headstage_notify_send();
headstage_notify_flip_buffer();
}
if ((dat_buf[1] & 0x28) == 0x28) {
dat_buf[0] = (dat_buf[0] << 1) | ((dat_buf[1] >> 7) & 0x01);
dat_buf[1] = (dat_buf[1] << 1) | ((dat_buf[2] >> 7) & 0x01);
dat_buf[2] = (dat_buf[2] << 1) | ((dat_buf[3] >> 7) & 0x01);
}
uint8_t channel;
if (INSTRUCTION.enable_channel_number == 1) {
channel = reverse_channel[INSTRUCTION.last_enable_channel];
} else if (dat_buf[0] == 0xc1) {
channel = reverse_channel[INSTRUCTION.last_enable_channel];
} else {
uint8_t channel_pointer = (INSTRUCTION.channel_pointer + 1) % INSTRUCTION.last_enable_channel;
INSTRUCTION.channel_pointer = channel_pointer;
channel = reverse_channel[INSTRUCTION.channel_mux[channel_pointer]];
}
// uint16_t data_value = (uint16_t)(((dat_buf[1] & 0x0F) << 6) | ((dat_buf[2] & 0xFC) >> 2));
uint8_t data_size = headstage_notify_append_data(channel, dat_buf);
if (data_size >= BLE_NOT_BUFF_SIZE) {
headstage_notify_send();
/*
events |= SPI_PERIODIC_EVT;
Semaphore_post(semaphore);
*/
}
headstage_spi_lsk_transaction(3);
/*
spi_lsk_transaction(3, NULL, spi_rxbuf);
*/
}
/*=====================
@@ -842,12 +938,15 @@ static void headstage_umc_state_transfer_ask() {
headstage_spi_lsk_transaction(8);
break;
case UMC_STATE_TRIGGER:
case UMC_STATE_CONTINUOUS:
case UMC_STATE_LIMITED:
headstage_spi_lsk_transaction(8);
break;
case UMC_STATE_WAIT_TRIGGER:
headstage_state = UMC_STATE_TRIGGER;
headstage_spi_lsk_transaction(3);
case UMC_STATE_CONTINUOUS:
headstage_spi_lsk_transaction(8);
break;
case UMC_STATE_LIMITED:
headstage_spi_lsk_transaction(8);
break;
case UMC_STATE_INTERRUPT:
break;
default:
break;
@@ -938,14 +1037,11 @@ static void headstage_umc_state_transfer_lsk() {
*/
case UMC_STATE_WAIT_START:
if (headstage_debug_buffer[1] > 18) {
// this transaction make cause amplifier data right shift
headstage_spi_lsk_transaction(3);
headstage_spi_lsk_transaction(7);
switch (INSTRUCTION.mode) {
default:
headstage_state = UMC_STATE_CONTINUOUS;
UMC_STATE.trigger_times = 0;
break;
case 3:
case 0:
// continuous mode
headstage_state = UMC_STATE_CONTINUOUS;
UMC_STATE.trigger_times = 0;
@@ -975,23 +1071,39 @@ static void headstage_umc_state_transfer_lsk() {
break;
case UMC_STATE_TRIGGER:
headstage_uni_umc_data_append_notify_buffer(spi_rxbuf);
// headstage_state = UMC_STATE_WAIT_TRIGGER;
// headstage_cpu_delay_ms(1);
// headstage_spi_lsk_transaction(3);
break;
case UMC_STATE_WAIT_TRIGGER:
// XXX how to back to UMC_STATE_TRIGGER state
headstage_spi_ask_transaction(4);
break;
case UMC_STATE_CONTINUOUS:
headstage_uni_umc_data_append_notify_buffer(spi_rxbuf);
// headstage_cpu_delay_ms(1);
// headstage_spi_lsk_transaction(3);
break;
case UMC_STATE_LIMITED:
headstage_uni_umc_data_append_notify_buffer(spi_rxbuf);
UMC_STATE.trigger_times--;
if (UMC_STATE.trigger_times == 0) {
headstage_state = UMC_STATE_WAIT_START;
}
// headstage_cpu_delay_ms(1);
// headstage_spi_lsk_transaction(3);
break;
case UMC_STATE_INTERRUPT:
break;
default:
@@ -8,7 +8,7 @@
#define HEADSTAGE_ZM_H
// product information
#define DEVICE_NAME "Elite-ZM-v1.4-re"
#define DEVICE_NAME "Elite-ZM-v1.2-30"
#define MAJOR_PRODUCT_NUMBER 0
#define MINOR_PRODUCT_NUMBER 2
#define MAJOR_VERSION_NUMBER 1
@@ -11,13 +11,17 @@
#include <ti/drivers/ADC.h>
#if defined(CC2650_LAUNCHXL)
#define CC2650_ADC0 CC2650_LAUNCHXL_ADC0
#define CC2650_ADC1 CC2650_LAUNCHXL_ADC1
#define CC2650_ADC2 CC2650_LAUNCHXL_ADC2
#elif defined(BOOSTXL_CC2650MA)
#define CC2650_ADC0 BOOSTXL_CC2650MA_ADC0
#define CC2650_ADC1 BOOSTXL_CC2650MA_ADC1
#define CC2650_ADC2 BOOSTXL_CC2650MA_ADC2
#define CC2650_ADC0 BOOSTXL_CC2650MA_ADC0 // DIO7
#define CC2650_ADC1 BOOSTXL_CC2650MA_ADC1 // DIO8
#define CC2650_ADC2 BOOSTXL_CC2650MA_ADC2 // DIO9
#endif
static ADC_Handle headstage_adc_handle_0;
@@ -31,10 +35,10 @@ static ADC_Handle headstage_adc_handle_2;
do { \
ADC_init(); \
ADC_Params param; \
ADC_Params_init(&params); \
ADC_Params_init(&param); \
headstage_adc_handle_0 = ADC_open(CC2650_ADC0, &param); \
headstage_adc_handle_1 = ADC_open(CC2650_ADC1, &param); \
headstage_adc_handle_2 = ADC_open(CC2650_ADC2, &param); \
} while (0)
#endif // HEADSTAGE_ADC_H
#endif // HEADSTAGE_ADC_H
@@ -13,17 +13,14 @@ static GPTimerCC26XX_Handle gptimer_handle_p1;
static GPTimerCC26XX_Handle gptimer_handle_s0;
static GPTimerCC26XX_Handle gptimer_handle_s1;
static void headstage_gptimer_perd_callback(GPTimerCC26XX_Handle handle, GPTimerCC26XX_IntMask interruptMask);
static void headstage_gptimer_step_callback(GPTimerCC26XX_Handle handle, GPTimerCC26XX_IntMask interruptMask);
static void headstage_sti_gptimer_main_callback(GPTimerCC26XX_Handle handle, GPTimerCC26XX_IntMask interruptMask);
static void headstage_sti_gptimer_step_callback(GPTimerCC26XX_Handle handle, GPTimerCC26XX_IntMask interruptMask);
#define headstage_gptimer_start(gptimer_handle) GPTimerCC26XX_start(gptimer_handle)
#define headstage_gptimer_stop(gptimer_handle) GPTimerCC26XX_stop(gptimer_handle)
#define headstage_gptimer_close(gptimer_handle) GPTimerCC26XX_close(gptimer_handle)
static void headstage_gptimer_open() {
// improve timer accuracy
// Power_setDependency(XOSC_HF);
GPTimerCC26XX_Params params;
GPTimerCC26XX_Params_init(&params);
@@ -32,19 +29,21 @@ static void headstage_gptimer_open() {
params.debugStallMode = GPTimerCC26XX_DEBUG_STALL_OFF;
gptimer_handle_p0 = GPTimerCC26XX_open(Board_GPTIMER0A, &params);
gptimer_handle_s0 = GPTimerCC26XX_open(Board_GPTIMER0B, &params);
gptimer_handle_p1 = GPTimerCC26XX_open(Board_GPTIMER1A, &params);
gptimer_handle_p1 = GPTimerCC26XX_open(Board_GPTIMER0B, &params);
GPTimerCC26XX_Params_init(&params);
params.width = GPT_CONFIG_16BIT;
params.mode = GPT_MODE_ONESHOT_DOWN;
params.debugStallMode = GPTimerCC26XX_DEBUG_STALL_OFF;
gptimer_handle_s0 = GPTimerCC26XX_open(Board_GPTIMER1A, &params);
gptimer_handle_s1 = GPTimerCC26XX_open(Board_GPTIMER1B, &params);
GPTimerCC26XX_setLoadValue(gptimer_handle_p0, 0xFFFFFF);
GPTimerCC26XX_setLoadValue(gptimer_handle_p1, 0xFFFFFF);
GPTimerCC26XX_setLoadValue(gptimer_handle_s0, 0xFFFFFF);
GPTimerCC26XX_setLoadValue(gptimer_handle_s1, 0xFFFFFF);
GPTimerCC26XX_registerInterrupt(gptimer_handle_p0, headstage_gptimer_perd_callback, GPT_INT_TIMEOUT);
GPTimerCC26XX_registerInterrupt(gptimer_handle_p1, headstage_gptimer_perd_callback, GPT_INT_TIMEOUT);
GPTimerCC26XX_registerInterrupt(gptimer_handle_s0, headstage_gptimer_step_callback, GPT_INT_TIMEOUT);
GPTimerCC26XX_registerInterrupt(gptimer_handle_s1, headstage_gptimer_step_callback, GPT_INT_TIMEOUT);
GPTimerCC26XX_registerInterrupt(gptimer_handle_p0, headstage_sti_gptimer_main_callback, GPT_INT_TIMEOUT);
GPTimerCC26XX_registerInterrupt(gptimer_handle_p1, headstage_sti_gptimer_main_callback, GPT_INT_TIMEOUT);
GPTimerCC26XX_registerInterrupt(gptimer_handle_s0, headstage_sti_gptimer_step_callback, GPT_INT_TIMEOUT);
GPTimerCC26XX_registerInterrupt(gptimer_handle_s1, headstage_sti_gptimer_step_callback, GPT_INT_TIMEOUT);
}
#define headstage_gptimer_set_load_value(gptimer_handle, load_value) GPTimerCC26XX_setLoadValue(gptimer_handle, load_value)
@@ -68,4 +67,6 @@ static void headstage_gptimer_open() {
GPTimerCC26XX_setLoadValue(gptimer_handle, _load); \
} while (0)
#define headstage_gptimer_set_callback(handle, callback) GPTimerCC26XX_registerInterrupt(handle, callback, GPT_INT_TIMEOUT);
#endif // HEADSTAGE_GPTIMER_H
@@ -1,37 +1,49 @@
/* Copyright (c) 2019. BioPro. Scientific.
*/
#ifndef HEADSTAGE_NOTIFY_TDC4VC3_H
#define HEADSTAGE_NOTIFY_TDC4VC3_H
/*
notify data format
==================
struct {
u8 device_id;
u8 data_length;
u32 cpu_timestamp;
u4 _;
u12 battery_voltage;
u4 sti_channel;
u12 sti_channel_voltage;
u16 sti_remind_times;
u4 sti_channel;
u12 sti_channel_voltage;
u16 sti_remind_times;
// total 16 bytes
}
*/
#ifndef HEADSTAGE_NOTIFY_STI_H
#define HEADSTAGE_NOTIFY_STI_H
#ifndef HEADSTAGE_NOTIFY_H
#error "headstage/headstage_notify.h not included"
#endif
#define NOT_BUF_OFFSET_INIT 6
#include "../headstage_notify_general.h"
static uint32_t not_buf_offset = NOT_BUF_OFFSET_INIT;
static uint32_t not_time_stamp = 0;
#define NOT_BUF_OFFSET_INIT 8
#define NOT_BUF_ALMOST_FULL 15
static void headstage_notify_set_timestamp() {
not_time_stamp = headstage_time_stamp_us();
#define headstage_notify_flip_buffer() _headstage_notify_flip_buffer(not_buf_offset);
headstage_notify_buffer[2] = not_time_stamp & 0xFF;
headstage_notify_buffer[3] = (not_time_stamp >> 8) & 0xFF;
headstage_notify_buffer[4] = (not_time_stamp >> 16) & 0xFF;
headstage_notify_buffer[5] = (not_time_stamp >> 24) & 0xFF;
}
static void headstage_notify_flip_buffer() {
uint8_t data_count = not_buf_offset;
headstage_notify_buffer[0] = CHIP_ID;
headstage_notify_buffer[1] = data_count;
not_buf_offset = NOT_BUF_OFFSET_INIT;
}
static uint8_t headstage_notify_append_data(uint8_t channel, uint16_t data_value) {
static uint8_t headstage_notify_append_data(uint8_t channel, uint16_t data_value, uint16_t times_remind) {
if (not_buf_offset <= NOT_BUF_OFFSET_INIT) {
headstage_notify_set_timestamp();
@@ -42,17 +54,24 @@ static uint8_t headstage_notify_append_data(uint8_t channel, uint16_t data_value
return not_buf_offset;
}
headstage_notify_buffer[not_buf_offset++] = ((channel & 0x0F) << 4) | ((data_value >> 8) & 0x0F);
headstage_notify_buffer[not_buf_offset++] = (data_value & 0xFF);
if (channel == CHANNEL_BATTERY) {
headstage_notify_buffer[6] = ((data_value >> 8) & 0x0F);
headstage_notify_buffer[7] = (data_value & 0xFF);
} else {
headstage_notify_buffer[not_buf_offset++] = ((channel & 0x0F) << 4) | ((data_value >> 8) & 0x0F);
headstage_notify_buffer[not_buf_offset++] = (data_value & 0xFF);
headstage_notify_buffer[not_buf_offset++] = ((times_remind >> 8) & 0xFF);
headstage_notify_buffer[not_buf_offset++] = (times_remind & 0xFF);
}
uint8_t ret = not_buf_offset;
if (not_buf_offset >= BLE_NOT_BUFF_SIZE) {
if (not_buf_offset >= NOT_BUF_ALMOST_FULL) {
headstage_notify_flip_buffer();
}
return ret;
}
#endif // HEADSTAGE_NOTIFY_TDC4VC3_H
#endif // HEADSTAGE_NOTIFY_STI_H
@@ -7,20 +7,8 @@
#if defined(CC2650_LAUNCHXL)
// clang-format off
#define PIN_PON1 IOID_5
#define PIN_POL1 IOID_6
#define PIN_POL0 IOID_10
#define PIN_PON0 IOID_11
#define PIN_TPS IOID_3
#define PIN_CUR IOID_4
#define PIN_VBAT IOID_7
#define PIN_SEN0 IOID_8
#define PIN_SEN1 IOID_9
// clang-format on
#elif defined(BOOSTXL_CC2650MA)
// clang-format off
#define PIN_LED_R IOID_6
#define PIN_LED_G IOID_7
#define PIN_PON1 IOID_9
#define PIN_POL1 IOID_14
#define PIN_POL0 IOID_13
@@ -32,6 +20,22 @@
#define PIN_SEN1 IOID_30
// clang-format on
#elif defined(BOOSTXL_CC2650MA)
// clang-format off
#define PIN_LED_R PIN_UNASSIGNED
#define PIN_LED_G PIN_UNASSIGNED
#define PIN_PON1 IOID_5
#define PIN_POL1 IOID_6
#define PIN_POL0 IOID_10
#define PIN_PON0 IOID_11
#define PIN_TPS IOID_3
#define PIN_CUR IOID_4
#define PIN_VBAT IOID_71
#define PIN_SEN0 IOID_8
#define PIN_SEN1 IOID_9
// clang-format on
#endif
static PIN_Config headstage_pin_configuration[] = { //
@@ -41,7 +45,10 @@ static PIN_Config headstage_pin_configuration[] = { //
PIN_PON0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL,
PIN_TPS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL,
PIN_LED_R | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
PIN_LED_G | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
//
PIN_TERMINATE};
#endif // HEADSTAGE_PIN_STI_H
#endif // HEADSTAGE_PIN_STI_H
@@ -8,53 +8,43 @@
#error "headstage/headstage_notify.h not included"
#endif
#include "../headstage_notify_general.h"
#define NOT_BUF_OFFSET_INIT 8
static uint32_t not_buf_offset = NOT_BUF_OFFSET_INIT;
static uint32_t not_time_stamp = 0;
#define headstage_notify_flip_buffer() _headstage_notify_flip_buffer((not_buf_offset - NOT_BUF_OFFSET_INIT) / 2);
static void headstage_notify_set_timestamp() {
not_time_stamp = headstage_time_stamp_us();
headstage_notify_buffer[2] = not_time_stamp & 0xFF;
headstage_notify_buffer[3] = (not_time_stamp >> 8) & 0xFF;
headstage_notify_buffer[4] = (not_time_stamp >> 16) & 0xFF;
headstage_notify_buffer[5] = (not_time_stamp >> 24) & 0xFF;
}
static void headstage_notify_flip_buffer() {
uint8_t data_count = (not_buf_offset - NOT_BUF_OFFSET_INIT) / 2;
headstage_notify_buffer[0] = CHIP_ID;
headstage_notify_buffer[1] = data_count;
not_buf_offset = NOT_BUF_OFFSET_INIT;
}
static uint8_t headstage_notify_append_data(uint8_t channel, uint8_t *data_value) {
static uint8_t headstage_notify_append_data(uint8_t channel, uint16_t *data_value) {
if (not_buf_offset <= NOT_BUF_OFFSET_INIT) {
headstage_notify_set_timestamp();
not_buf_offset = NOT_BUF_OFFSET_INIT;
}
if (not_buf_offset >= BLE_NOT_BUFF_SIZE) {
return not_buf_offset;
}
if (data_value == NULL) {
headstage_notify_buffer[not_buf_offset++] = ((channel & 0x0F) << 4);
headstage_notify_buffer[not_buf_offset++] = 0x03;
} else {
headstage_notify_buffer[not_buf_offset++] = ((channel & 0x0f) << 4) | (data_value[1] & 0x0f);
headstage_notify_buffer[not_buf_offset++] = data_value[2] & 0xFC;
}
if (not_buf_offset == BLE_NOT_BUFF_SIZE) {
uint32_t current = headstage_time_stamp_us();
uint32_t time_delta = ((current - not_time_stamp)) & 0xFFFF;
headstage_notify_buffer[6] = time_delta & 0xFF;
headstage_notify_buffer[7] = (time_delta >> 8) & 0xFF;
headstage_notify_buffer[not_buf_offset++] = ((channel & 0x0F) << 4) | ((*data_value >> 6) & 0x0F);
headstage_notify_buffer[not_buf_offset++] = ((*data_value << 2) & 0xFC);
}
uint8_t ret = not_buf_offset;
if (not_buf_offset >= BLE_NOT_BUFF_SIZE) {
uint32_t current = headstage_time_stamp();
uint32_t time_delta = (current - not_time_stamp) & 0xFFFF;
headstage_notify_buffer[6] = time_delta & 0xFF;
headstage_notify_buffer[7] = (time_delta >> 8) & 0xFF;
headstage_notify_flip_buffer();
}
return ret;
}
@@ -2,4 +2,4 @@
*/
#ifndef HEADSTAGE_ADC_H
#define HEADSTAGE_ADC_H
#endif // HEADSTAGE_ADC_H
#endif // HEADSTAGE_ADC_H
@@ -1,417 +0,0 @@
/*
* this header file need to be modified, to control
*/
#include "Python.h"
#include "structmember.h"
#ifdef _RASPBERRY_PI3_
#include <wiringPi.h>
#else
#include "wiringPi.h"
#endif
#define SPI_SPEED_US 100
// class Bpsspi
typedef struct {
PyObject_HEAD;
unsigned int cpol;
unsigned int cpha;
unsigned int clk;
unsigned int mosi;
int miso;
unsigned int cs_sz;
unsigned int *cs;
} Bpsspi;
// Bpsspi __init__
static PyObject *Bpsspi_new(PyTypeObject *type, PyObject *args, PyObject *keywords);
static int Bpsspi_init(Bpsspi *self, PyObject *args, PyObject *kwargs);
static void Bpsspi_dealloc(Bpsspi *self);
// member
static PyMemberDef BpsspiMembers[] = { //
{"cpol", T_UINT, offsetof(Bpsspi, cpol), READONLY, "polarity"},
{"cpha", T_UINT, offsetof(Bpsspi, cpha), READONLY, "phase"},
{"clk", T_UINT, offsetof(Bpsspi, clk), READONLY, "clock pin"},
{"mosi", T_UINT, offsetof(Bpsspi, mosi), READONLY, "mosi pin"},
{"miso", T_INT, offsetof(Bpsspi, miso), READONLY, "miso pin"},
{"cs_sz", T_UINT, offsetof(Bpsspi, cs_sz), READONLY, "chip selection pins number"},
{NULL}};
// methods
static PyObject *Bpsspi_reset(Bpsspi *self);
static PyObject *Bpsspi_set_cs(Bpsspi *self, PyObject *args, PyObject *kwargs);
static PyObject *Bpsspi_send_byte_transmit(Bpsspi *self, PyObject *args, PyObject *kwargs);
static PyObject *Bpsspi_send_byte_exchange(Bpsspi *self, PyObject *args, PyObject *kwargs);
static PyMethodDef BpsspiMethods[] = { //
{"reset", (PyCFunction)Bpsspi_reset, METH_NOARGS, "Bpsspi.reset"},
// set_cs(self, cs:int, output:bool)
{"set_cs", (PyCFunction)Bpsspi_set_cs, METH_VARARGS | METH_KEYWORDS, "Bpsspi.set_cs"},
// send_byte_transmit(self, data:bytes)
{"send_byte_transmit", (PyCFunction)Bpsspi_send_byte_transmit, METH_VARARGS | METH_KEYWORDS, "Bpsspi.send_byte_transmit"},
// send_byte_exchange(self, data:bytes) -> List[int]
{"send_byte_exchange", (PyCFunction)Bpsspi_send_byte_exchange, METH_VARARGS | METH_KEYWORDS, "Bpsspi.send_byte_exchange"},
{NULL}};
static PyTypeObject BpsspiType = {
PyVarObject_HEAD_INIT(NULL, 0) //,
.tp_name = "Bpsspi",
.tp_doc = "BPS spi",
.tp_basicsize = sizeof(Bpsspi),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_new = Bpsspi_new,
.tp_init = (initproc)Bpsspi_init,
.tp_dealloc = (destructor)Bpsspi_dealloc,
.tp_members = BpsspiMembers,
.tp_methods = BpsspiMethods,
};
// function implement
static PyObject *Bpsspi_new(PyTypeObject *type, PyObject *args, PyObject *keywords) {
Bpsspi *self = (Bpsspi *)type->tp_alloc(type, 0);
if (self != NULL) {
self->cpol = 0;
self->cpha = 0;
self->clk = 0;
self->mosi = 0;
self->miso = -1;
self->cs_sz = 0;
self->cs = NULL;
}
return (PyObject *)self;
}
static int Bpsspi_init_cs(Bpsspi *self) {
if (self->cs != NULL) {
PyMem_Free(self->cs);
self->cs = NULL;
}
self->cs = (unsigned int *)PyMem_Malloc(self->cs_sz * sizeof(unsigned int));
if (self->cs == NULL) {
PyErr_SetString(PyExc_RuntimeError, "PyMem_Malloc cs fail");
return 1;
}
return 0;
}
static int Bpsspi_init(Bpsspi *self, PyObject *args, PyObject *kwargs) {
static char *keywords[] = {"clk", "mosi", "miso", "cs", "cpol", "cpha", NULL};
unsigned int clk;
unsigned int mosi;
PyObject * miso = NULL;
PyObject * cs = NULL;
int cpol = 0;
int cpha = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "II|OOpp", keywords, &clk, &mosi, &miso, &cs, &cpol, &cpha)) return -1;
self->clk = clk;
self->mosi = mosi;
self->cpol = cpol > 0;
self->cpha = cpha > 0;
// miso
if (miso == NULL || miso == Py_None) {
self->miso = -1;
} else if (PyLong_Check(miso)) {
int miso_val = (int)PyLong_AsLong(miso);
if (miso_val < 0) {
PyErr_Format(PyExc_ValueError, "negative miso pin %d", miso_val);
return -1;
}
self->miso = miso_val;
} else {
PyErr_SetString(PyExc_ValueError, "illegal miso type");
return -1;
}
// cs
if (cs == NULL || cs == Py_None) {
self->cs_sz = 0;
self->cs = NULL;
} else if (PyLong_Check(cs)) {
self->cs_sz = 1;
Bpsspi_init_cs(self);
int cs_val = (int)PyLong_AsLong(cs);
if (cs_val < 0) {
PyErr_Format(PyExc_ValueError, "negative cs pin %d", cs_val);
return -1;
}
*self->cs = cs_val;
} else if (PyTuple_Check(cs)) {
self->cs_sz = PyTuple_GET_SIZE(cs);
Bpsspi_init_cs(self);
for (unsigned int i = 0; i < self->cs_sz; i++) {
PyObject *cs_ref = PyTuple_GetItem(cs, i);
if (cs_ref == NULL) return -1;
int cs_val = (int)PyLong_AsLong(cs_ref);
if (cs_val == -1 && PyErr_Occurred()) return -1;
if (cs_val < 0) {
PyErr_Format(PyExc_ValueError, "negative cs pin %d", cs_val);
return -1;
}
*(self->cs + i) = cs_val;
}
} else {
PyErr_SetString(PyExc_ValueError, "illegal cs type");
return -1;
}
// reset
Bpsspi_reset(self);
return 0;
}
static void Bpsspi_dealloc(Bpsspi *self) {
if (self->cs != NULL) {
PyMem_Free(self->cs);
self->cs = NULL;
}
Py_TYPE(self)->tp_free((PyObject *)self);
}
static PyObject *Bpsspi_reset(Bpsspi *self) {
pinMode(self->clk, OUTPUT);
digitalWrite(self->clk, (self->cpol) ? HIGH : LOW);
pinMode(self->mosi, OUTPUT);
digitalWrite(self->mosi, LOW);
if (self->miso >= 0) {
pinMode(self->miso, INPUT);
pullUpDnControl(self->miso, LOW);
}
if (self->cs_sz > 0) {
for (unsigned int i = 0; i < self->cs_sz; i++) {
pinMode(*(self->cs + i), OUTPUT);
digitalWrite(*(self->cs + i), HIGH);
}
}
Py_RETURN_NONE;
}
static int Bpsspi_set_cs0(Bpsspi *self, unsigned int cs, int output) {
if (self->cs_sz == 0) return 0;
for (unsigned int i = 0; i < self->cs_sz; i++) {
if (cs == *(self->cs + i)) {
digitalWrite(*(self->cs + i), output);
return 1;
}
}
return 0;
}
static PyObject *Bpsspi_set_cs(Bpsspi *self, PyObject *args, PyObject *kwargs) {
static char *keywords[] = {"cs", "output", NULL};
unsigned int cs;
int hl = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ip", keywords, &cs, &hl)) return NULL;
if (self->cs_sz == 0) {
Py_RETURN_NONE;
}
Bpsspi_set_cs0(self, cs, hl ? HIGH : LOW);
Py_RETURN_NONE;
}
static PyObject *Bpsspi_send_byte_transmit(Bpsspi *self, PyObject *args, PyObject *kwargs) {
static char *keywords[] = {"data", NULL};
PyObject *data_ref;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", keywords, &data_ref)) return NULL;
if (!PyBytes_Check(data_ref)) {
PyErr_SetString(PyExc_ValueError, "data not bytes");
return NULL;
}
Py_ssize_t data_sz = PyBytes_GET_SIZE(data_ref);
char * data = PyBytes_AS_STRING(data_ref);
Py_BEGIN_ALLOW_THREADS
int clk_0 = (self->cpol) ? HIGH : LOW;
int clk_1 = (self->cpol) ? LOW : HIGH;
digitalWrite(self->clk, clk_0);
for (unsigned int i = 0; i < data_sz; i++) {
char d = data[i];
for (int j = 7; j >= 0; j--) {
int v = (d & (1 << j)) > 0;
if (self->cpha) {
digitalWrite(self->clk, clk_1);
delayMicroseconds(SPI_SPEED_US);
digitalWrite(self->mosi, (v) ? HIGH : LOW);
digitalWrite(self->clk, clk_0);
} else {
digitalWrite(self->mosi, (v) ? HIGH : LOW);
digitalWrite(self->clk, clk_1);
delayMicroseconds(SPI_SPEED_US);
digitalWrite(self->clk, clk_0);
}
delayMicroseconds(SPI_SPEED_US);
}
}
digitalWrite(self->clk, clk_0);
Py_END_ALLOW_THREADS
Py_RETURN_NONE;
}
// XXX not tested
static PyObject *Bpsspi_send_byte_exchange(Bpsspi *self, PyObject *args, PyObject *kwargs) {
if (self->miso < 0) {
PyErr_SetString(PyExc_RuntimeError, "miso pin not set");
}
static char *keywords[] = {"data", NULL};
PyObject *data_ref;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", keywords, &data_ref)) return NULL;
if (!PyBytes_Check(data_ref)) {
PyErr_SetString(PyExc_ValueError, "data not bytes");
return NULL;
}
Py_ssize_t data_sz = PyBytes_GET_SIZE(data_ref);
char * data = PyBytes_AS_STRING(data_ref);
PyObject *ret = PyList_New(data_sz);
if (ret == NULL) return NULL;
Py_BEGIN_ALLOW_THREADS
int clk_0 = (self->cpol) ? HIGH : LOW;
int clk_1 = (self->cpol) ? LOW : HIGH;
digitalWrite(self->clk, clk_0);
for (unsigned int i = 0; i < data_sz; i++) {
char d = data[i];
int r = 0;
for (int j = 7; j >= 0; j--) {
int v = (d & (1 << j)) > 0;
if (self->cpha) {
digitalWrite(self->clk, clk_1);
delayMicroseconds(SPI_SPEED_US);
digitalWrite(self->mosi, (v) ? HIGH : LOW);
digitalWrite(self->clk, clk_0);
delayMicroseconds(SPI_SPEED_US);
if (digitalRead(self->miso)) {
r |= (1 << j);
}
} else {
digitalWrite(self->mosi, (v) ? HIGH : LOW);
digitalWrite(self->clk, clk_1);
delayMicroseconds(SPI_SPEED_US);
if (digitalRead(self->miso)) {
r |= (1 << j);
}
digitalWrite(self->clk, clk_0);
delayMicroseconds(SPI_SPEED_US);
}
}
PyList_SET_ITEM(ret, i, PyLong_FromLong(r));
}
digitalWrite(self->clk, clk_0);
Py_END_ALLOW_THREADS
return ret;
}
// module init
static PyMethodDef moduleMethods[] = { //
{NULL, NULL, 0, NULL}};
static struct PyModuleDef BpsspiModule = { //
PyModuleDef_HEAD_INIT,
// module name
"bpsspi",
// module doc
NULL,
-1,
moduleMethods};
// module export
PyMODINIT_FUNC PyInit_bpsspi(void) {
wiringPiSetupPhys();
PyObject *module;
module = PyModule_Create(&BpsspiModule);
if (module == NULL) return NULL;
if (PyType_Ready(&BpsspiType) < 0) return NULL;
Py_INCREF(&BpsspiType);
PyModule_AddObject(module, "Bpsspi", (PyObject *)&BpsspiType);
return module;
}
@@ -0,0 +1,53 @@
/* Copyright (c) 2019. BioPro. Scientific.
*/
#ifndef HEADSTAGE_NOTIFY_TDC4VAF2_H
#define HEADSTAGE_NOTIFY_TDC4VAF2_H
#ifndef HEADSTAGE_NOTIFY_H
#error "headstage/headstage_notify.h not included"
#endif
#include "../headstage_notify_general.h"
#define NOT_BUF_OFFSET_INIT 8
#define headstage_notify_flip_buffer() _headstage_notify_flip_buffer((not_buf_offset - NOT_BUF_OFFSET_INIT) / 2);
static uint8_t headstage_notify_append_data(uint8_t channel, uint8_t *data_value) {
if (not_buf_offset <= NOT_BUF_OFFSET_INIT) {
headstage_notify_set_timestamp();
not_buf_offset = NOT_BUF_OFFSET_INIT;
}
if (not_buf_offset == NOT_BUF_OFFSET_INIT + 2) {
uint32_t current = headstage_time_stamp();
uint32_t time_delta = ((current - not_time_stamp) >> 1) & 0xFFFF;
headstage_notify_buffer[6] = time_delta & 0xFF;
headstage_notify_buffer[7] = (time_delta >> 8) & 0xFF;
}
if (not_buf_offset >= BLE_NOT_BUFF_SIZE) {
return not_buf_offset;
}
if (data_value == NULL) {
headstage_notify_buffer[not_buf_offset++] = ((channel & 0x0F) << 4);
headstage_notify_buffer[not_buf_offset++] = 0x03;
} else {
headstage_notify_buffer[not_buf_offset++] = ((channel & 0x0f) << 4) | (data_value[1] & 0x0f);
headstage_notify_buffer[not_buf_offset++] = data_value[2] & 0xFC;
}
uint8_t ret = not_buf_offset;
if (not_buf_offset >= BLE_NOT_BUFF_SIZE) {
headstage_notify_flip_buffer();
}
return ret;
}
#endif // HEADSTAGE_NOTIFY_TDC4VAF2_H
@@ -1,64 +1,64 @@
{
"name": "Neulive",
"version": "1.3",
"version": "0.2",
"match_rule": {
"local_name_pattern": "Neulive.*",
"major_product_number": 1,
"minor_product_number": 1,
"major_version_number": 1,
"minor_version_number": 3
"major_version_number": 0,
"minor_version_number": 2
},
"constant": {
"REC_CHANNEL_COUNT": 12,
"REC_CHANNEL_COUNT": 13,
"STI_CHANNEL_COUNT": 4,
"ADC_SAMPLE_RATE_LIST": [
2000,
3800,
7600,
15200,
30400
10000,
19000,
38000,
76000,
152000
],
"STI_FREQ_LIST": [
6,
8,
10,
12,
14,
16,
18,
20,
22,
24,
26,
28,
30,
32,
34,
36,
38,
40,
50,
60,
70,
80,
90,
100,
110,
120,
130,
140,
150,
160,
170,
180,
190,
200,
400,
600,
800,
1000,
1200,
1400,
1600,
1800,
2000
2000,
3000,
4000,
5000,
6000,
7000,
8000,
9000,
10000
],
"STI_PULSE_WIDTH": [
80,
180,
280,
380,
480,
580,
680,
780,
880,
980
40,
90,
140,
190,
240,
290,
340,
390,
440,
490
]
},
"parameters": {
@@ -84,22 +84,22 @@
"description": "amp gain",
"record_meta": true,
"value": [
3,
14,
27,
60,
280,
540
2,
5,
10,
200,
500,
1000
]
},
"LOW_FREQ_BAND": {
"description": "low pass filter",
"description": "",
"record_meta": true,
"domain": [
8
]
},
"STI_MODE": {
"STI_BEHAVIOR": {
"description": "how to execute stimulus",
"value": [
"DISABLE",
@@ -108,8 +108,8 @@
"CONTINUOUS"
]
},
"STI_WAVEFORM": {
"description": "describe the waveform of stimulation",
"STI_MODE": {
"description": "stimulation mode",
"value": [
"Positive Pulse",
"Negative Pulse",
@@ -118,13 +118,13 @@
"Arbitrary Waveform"
]
},
"STI_AMPERE": {
"description": "stimulation ampere, unit: uA ",
"STI_VOLT": {
"description": "stimulation voltage",
"type": "float",
"domain": [
32
],
"value": " 31 * VALUE "
"value": "2 + 3 * VALUE / 31"
},
"STI_TIMES": {
"description": "how many times will be executed",
@@ -162,27 +162,17 @@
"value": "STI_PULSE_WIDTH[VALUE]"
},
"CHOPPER": {
"description": "default_disable",
"description": "",
"domain": "bool"
},
"FAST_SETTLE": {
"description": "protect amplifier input when stimulation is executed",
"description": "",
"domain": "bool"
},
"UMC_TEST": {
"description": "start umc test mode",
"domain": "action",
"on_change": "umc_default"
},
"UMC_RESET": {
"description": "reset headstage to perform another setting",
"domain": "action",
"on_change": "reset"
},
"UMC_TRIGGER": {
"description": "trigger stimulation when device is in trigger mode",
"domain": "action",
"on_change": "STIMULUS"
}
},
"instruction": {
@@ -191,19 +181,12 @@
"expression": "len(CHANNEL) > 0",
"raise": "no recording channel"
},
"data_format",
"_notify(True)",
"start_recording",
"umc_parameter",
"_sync(True)",
"VIS_STI"
],
"trigger stimulation": [
"umc_sti_trigger0"
],
"umc_reset": [
"VIS_RST"
],
"data_format": [
"_data_format('TDC4VAF2')"
],
@@ -211,45 +194,40 @@
"type": "RIS",
"data": [
"3b101#direct header;2b0#don't care;3b>LOW_FREQ_BAND",
"2b0#don't care;1bCHOPPER;1bFAST_SETTLE;3b>STI_WAVEFORM",
"5b>STI_AMPERE;4b>STI_PMOS",
"4b0#don't care;1bCHOPPER;1bFAST_SETTLE",
"5b>STI_VOLT;4b>STI_PMOS",
"4b>STI_NMOS;4b>SAMPLE_RATE"
]
},
"umc_parameter": {
"type": "RIS",
"foreach-parameter": {
"parameter": "CHANNEL",
"variable": [
"a",
"b",
"c",
"d"
]
},
"data": [
"3b001#umc parameter header;3b>AMP_GAIN",
"4b>PULSE_WIDTH;6b>STI_TIMES",
"2b>STI_MODE;6b>STI_FREQ",
"1ba?;1bb?;1bc?;1bd?",
"4b>a?:0;4b>b?:0",
"4b>c?:0;4b>d?:0"
"3b001#umc parameter header",
"3b>AMP_GAIN;4b>PULSE_WIDTH",
"6b>STI_TIMES;2b>STI_BEHAVIOR",
"6b>STI_FREQ"
]
},
"umc_default": [
"_set('CHANNEL', 0)",
"_set('SAMPLE_RATE', 0)",
"_set('AMP_GAIN', 5)",
"_set('STI_WAVEFORM', 1)",
"_set('STI_MODE', 1)",
"_set('STI_NMOS', 0)",
"_set('STI_PMOS', 1)",
"_set('STI_AMPERE', 0)",
"_set('CHANNEL', 3)",
"_set('CHANNEL', 4)",
"_set('CHANNEL', 5)",
"_set('CHANNEL', 6)",
"_set('CHANNEL', 7)",
"_set('CHANNEL', 8)",
"_set('SAMPLE_RATE', 9)",
"_set('AMP_GAIN', 3)",
"_set('STI_BEHAVIOR', 1)",
"_set('STI_MODE', 0)",
"_set('STI_NMOS', STI_PMOS + 1)",
"_set('STI_PMOS', 0)",
"_set('STI_NMOS', 1)",
"_set('STI_VOLT', 0)",
"_set('STI_FREQ', 0)",
"_set('STI_TIMES', 0)",
"_set('PULSE_WIDTH', 0)",
"_set('FAST_SETTLE', 1)",
"_set('CHOPPER', 0)",
"_set('FAST_SETTLE', 0)",
"_set('CHOPPER', 1)",
"data_format",
"_notify(True)",
"umc_default0",
@@ -261,14 +239,6 @@
"data": [
"1B0#load umc default parameter into uni"
]
},
"umc_sti_trigger0": {
"type": "RIS",
"description": "this function is perform only in trigger mode",
"data": [
"1BC0# trigger stimulation when recording is performed"
]
}
}
}
@@ -5,60 +5,60 @@
"local_name_pattern": "Neulive.*",
"major_product_number": 1,
"minor_product_number": 1,
"major_version_number": 1,
"major_version_number": 0,
"minor_version_number": 2
},
"constant": {
"REC_CHANNEL_COUNT": 13,
"STI_CHANNEL_COUNT": 4,
"ADC_SAMPLE_RATE_LIST": [
2000,
3800,
7600,
15200,
30400
10000,
19000,
38000,
76000,
152000
],
"STI_FREQ_LIST": [
6,
8,
10,
12,
14,
16,
18,
20,
22,
24,
26,
28,
30,
32,
34,
36,
38,
40,
50,
60,
70,
80,
90,
100,
110,
120,
130,
140,
150,
160,
170,
180,
190,
200,
400,
600,
800,
1000,
1200,
1400,
1600,
1800,
2000
2000,
3000,
4000,
5000,
6000,
7000,
8000,
9000,
10000
],
"STI_PULSE_WIDTH": [
80,
180,
280,
380,
480,
580,
680,
780,
880,
980
40,
90,
140,
190,
240,
290,
340,
390,
440,
490
]
},
"parameters": {
@@ -84,12 +84,12 @@
"description": "amp gain",
"record_meta": true,
"value": [
3,
40,
70,
30,
400,
700
2,
5,
10,
200,
500,
1000
]
},
"LOW_FREQ_BAND": {
@@ -99,7 +99,7 @@
8
]
},
"STI_MODE": {
"STI_BEHAVIOR": {
"description": "how to execute stimulus",
"value": [
"DISABLE",
@@ -108,8 +108,8 @@
"CONTINUOUS"
]
},
"STI_WAVEFORM": {
"description": "describe the waveform of stimulation",
"STI_MODE": {
"description": "stimulation mode",
"value": [
"Positive Pulse",
"Negative Pulse",
@@ -119,12 +119,12 @@
]
},
"STI_VOLT": {
"description": "stimulation volt, unit: V ",
"description": "stimulation voltage",
"type": "float",
"domain": [
32
],
"value": " 2 + 3 * VALUE / 31"
"value": "2 + 3 * VALUE / 31"
},
"STI_TIMES": {
"description": "how many times will be executed",
@@ -162,27 +162,17 @@
"value": "STI_PULSE_WIDTH[VALUE]"
},
"CHOPPER": {
"description": "default_disable",
"description": "",
"domain": "bool"
},
"FAST_SETTLE": {
"description": "protect amplifier input when stimulation is executed",
"description": "",
"domain": "bool"
},
"UMC_TEST": {
"description": "start umc test mode",
"domain": "action",
"on_change": "umc_default"
},
"UMC_RESET": {
"description": "reset headstage to perform another setting",
"domain": "action",
"on_change": "reset"
},
"UMC_TRIGGER": {
"description": "trigger stimulation when device is in trigger mode",
"domain": "action",
"on_change": "STIMULUS"
}
},
"instruction": {
@@ -198,10 +188,10 @@
"_sync(True)",
"VIS_STI"
],
"trigger stimulation": [
"umc_sti_trigger0"
"stop": [
"VIS_INT"
],
"umc_reset": [
"restart": [
"VIS_RST"
],
"data_format": [
@@ -211,7 +201,7 @@
"type": "RIS",
"data": [
"3b101#direct header;2b0#don't care;3b>LOW_FREQ_BAND",
"2b0#don't care;1bCHOPPER;1bFAST_SETTLE;3b>STI_WAVEFORM",
"2b0#don't care;1bCHOPPER;1bFAST_SETTLE;3b>STI_MODE",
"5b>STI_VOLT;4b>STI_PMOS",
"4b>STI_NMOS;4b>SAMPLE_RATE"
]
@@ -230,26 +220,27 @@
"data": [
"3b001#umc parameter header;3b>AMP_GAIN",
"4b>PULSE_WIDTH;6b>STI_TIMES",
"2b>STI_MODE;6b>STI_FREQ",
"2b>STI_BEHAVIOR;6b>STI_FREQ",
"1ba?;1bb?;1bc?;1bd?",
"4b>a?:0;4b>b?:0",
"4b>c?:0;4b>d?:0"
]
},
"umc_default": [
"_set('CHANNEL', 0)",
"_set('CHANNEL', 1)",
"_set('SAMPLE_RATE', 0)",
"_set('AMP_GAIN', 5)",
"_set('STI_WAVEFORM', 1)",
"_set('STI_MODE', 1)",
"_set('STI_NMOS', 0)",
"_set('STI_PMOS', 1)",
"_set('STI_BEHAVIOR', 1)",
"_set('STI_MODE', 0)",
"_set('STI_NMOS', STI_PMOS + 1)",
"_set('STI_PMOS', 0)",
"_set('STI_NMOS', 1)",
"_set('STI_VOLT', 0)",
"_set('STI_FREQ', 0)",
"_set('STI_TIMES', 0)",
"_set('PULSE_WIDTH', 0)",
"_set('FAST_SETTLE', 1)",
"_set('CHOPPER', 0)",
"_set('FAST_SETTLE', 0)",
"_set('CHOPPER', 1)",
"data_format",
"_notify(True)",
"umc_default0",
@@ -261,14 +252,6 @@
"data": [
"1B0#load umc default parameter into uni"
]
},
"umc_sti_trigger0": {
"type": "RIS",
"description": "this function is perform only in trigger mode",
"data": [
"1BC0# trigger stimulation when recording is performed"
]
}
}
}
@@ -1,64 +0,0 @@
/* Copyright (c) 2019. BioPro. Scientific.
*/
#ifndef NEULIVE_1P2
#define NEULIVE_1P2
/*============================
==== product information ====
===========================*/
#define DEVICE_NAME "Neulive-v1.2"
#define MAJOR_PRODUCT_NUMBER 1
#define MINOR_PRODUCT_NUMBER 1
#define MAJOR_VERSION_NUMBER 1 // need to modify
#define MINOR_VERSION_NUMBER 2
static uint16_t sti_channel_table[4] = {
{0b000001}, // 2
{0b000111}, // 8
{0b001011}, // 12
{0b001111} // 16
};
static uint16_t reverse_channel[16] = {{0x0A}, // 1
{0x0B},
{0x00},
{0x01},
{0x02},
{0x07},
{0x06},
{0x03},
{0x05},
{0x04},
{0x08},
{0xff},
{0x0c},
{0x09},
{0xff},
{0xff}};
static uint16_t amp_channel_table[13] = { //
{0x03},
{0x04},
{0x05},
{0x08},
{0x0A},
{0x09},
{0x07},
{0x06},
{0x0B},
{0x0E},
{0x01},
{0x02},
{0x0D}};
static uint16_t amp_gain_table[] = {
0b100011, // 3
0b000011, // 30
0b101100, // 40
0b101001, // 70
0b001100, // 400
0b001001, // 700
};
#endif
@@ -1,63 +0,0 @@
/* Copyright (c) 2019. BioPro. Scientific.
*/
#ifndef NEULIVE_1P3
#define NEULIVE_1P3
/*============================
==== product information ====
===========================*/
#define DEVICE_NAME "Neulive-v1.3"
#define MAJOR_PRODUCT_NUMBER 1
#define MINOR_PRODUCT_NUMBER 1
#define MAJOR_VERSION_NUMBER 1
#define MINOR_VERSION_NUMBER 3
static uint16_t sti_channel_table[4] = {
{0b000010}, // 3
{0b000011}, // 4
{0b000100}, // 5
{0b000101} // 6
};
static uint16_t reverse_channel[16] = {{0x0A}, // 1
{0x00},
{0x01},
{0x02},
{0x03},
{0x08},
{0x07},
{0x06},
{0x05},
{0x04},
{0x09},
{0x0B},
{0xFF},
{0xFF},
{0xff},
{0xff}};
static uint16_t amp_channel_table[12] = { //
{0x02},
{0x03},
{0x04},
{0x05},
{0x0A},
{0x09},
{0x08},
{0x07},
{0x06},
{0x0b},
{0x01},
{0x0C}};
static uint16_t amp_gain_table[] = {
0b100011, // 3
0b101100, // 14
0b101001, // 27
0b000011, // 60
0b001100, // 280
0b001001, // 540
};
#endif
@@ -4,37 +4,14 @@
#define HEADSTAGE_PIN_ZM_H
// clang-format off
#define PIN_ADC_CS IOID_8
#define PIN_DAC_CS IOID_9
#define PIN_SWITCH_ON IOID_11
#define PIN_SHUTDOWN_6994 IOID_10
#define PIN_ADC_CS IOID_2
#define PIN_DAC_CS IOID_4
#define PIN_SWITCH_ON IOID_10
#define PIN_SHUTDOWN_6994 IOID_11
#define PIN_ENABLE_V10 IOID_12
#define PIN_ENABLE_V05 IOID_13
#define PIN_TURNON_200R IOID_5
#define PIN_TURNON_10K IOID_6
/* I2C */
#ifdef ELITE_I2C
#define Board_I2C0_SCL0 IOID_7
#define Board_I2C0_SDA0 IOID_1
#endif
#define PIN_ENABLE_V05 IOID_14
// clang-format on
// from Elite IV-test branch
/* SPI Board */
#define Board_SPI0_MISO PIN_UNASSIGNED
#define Board_SPI0_MOSI IOID_1
#define Board_SPI0_CLK IOID_0
#define Board_SPI0_CS PIN_UNASSIGNED
#define Board_SPI1_MISO IOID_3
#define Board_SPI1_MOSI IOID_2
#define Board_SPI1_CLK IOID_4
#define Board_SPI1_CS PIN_UNASSIGNED
// End of Elite IV-test branch
#if defined(CC2650_LAUNCHXL)
#define PIN_LED_R IOID_6
#define PIN_LED_G IOID_7
@@ -45,9 +22,6 @@ static PIN_Config headstage_pin_configuration[] = { //
PIN_ADC_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL,
PIN_DAC_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL,
PIN_TURNON_200R | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL,
PIN_TURNON_10K | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL,
PIN_ENABLE_V10 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL,
PIN_ENABLE_V05 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL,
@@ -36,23 +36,14 @@ static SPI_Transaction headstage_spi_adc_transaction;
#define headstage_spi_open() \
do { \
SPI_init(); \
SPI_Params spi_parameter0; \
SPI_Params_init(&spi_parameter0); \
SPI_Params spi_parameter; \
SPI_Params_init(&spi_parameter); \
spi_parameter.transferMode = SPI_MODE_BLOCKING; \
spi_parameter.mode = SPI_MASTER; \
spi_parameter.bitRate = 2000; \
spi_parameter.dataSize = 16; \
spi_parameter.frameFormat = SPI_POL0_PHA1; \
headstage_spi_dac_handle = SPI_open(Board_SPI0, &spi_parameter0);\
SPI_Params spi_parameter1; \
SPI_Params_init(&spi_parameter1); \
spi_parameter.transferMode = SPI_MODE_BLOCKING; \
spi_parameter.mode = SPI_MASTER; \
spi_parameter.bitRate = 1000000; \
spi_parameter.bitRate = 12000000; \
spi_parameter.dataSize = 8; \
spi_parameter.frameFormat = SPI_POL0_PHA1; \
headstage_spi_dac_handle = SPI_open(Board_SPI1, &spi_parameter1);\
spi_parameter.frameFormat = SPI_POL0_PHA0; \
headstage_spi_dac_handle = SPI_open(Board_SPI0, &spi_parameter); \
} while (0)
#define headstage_dac_transaction() \
@@ -184,7 +184,7 @@ typedef struct {
static ICall_EntityID self;
// Semaphore globally used to post events to the application thread
ICall_Semaphore semaphore;
static ICall_Semaphore semaphore;
// Queue object used for app messages
static Queue_Struct application_message;
@@ -221,7 +221,6 @@ static void SimpleBLEPeripheral_sendAttRsp(void);
static void SimpleBLEPeripheral_freeAttRsp(uint8_t status);
static void SimpleBLEPeripheral_stateChangeCB(gaprole_States_t newState);
static void SimpleBLEPeripheral_enqueueMsg(uint8_t event, uint8_t state);
static void headstage_data_length_extension();
#ifndef FEATURE_OAD_ONCHIP
static void SimpleBLEPeripheral_charValueChangeCB(uint8_t paramID);
@@ -409,11 +408,6 @@ static void SimpleBLEPeripheral_init(void) {
GATT_RegisterForMsgs(self);
HCI_LE_ReadMaxDataLenCmd();
HCI_LE_WriteSuggestedDefaultDataLenCmd(251, 2120); // this is used for data length extension
uint8_t prepare_write_req = 6;
GATTServApp_SetParameter(GATT_PARAM_NUM_PREPARE_WRITES, 1, &prepare_write_req);
}
#ifndef DEVICE_NAME
@@ -446,8 +440,9 @@ static void SimpleBLEPeripheral_init(void) {
#endif
static char *date = __DATE__;
static void headstage_init_device_info() {
static void headstage_init_device_info() {
static char *date = __DATE__;
uint8_t year = 10 * (date[9] - '0') + (date[10] - '0');
uint8_t month = 0;
@@ -504,21 +499,14 @@ static void headstage_init_device_info() {
break;
}
uint8_t scanRspData[64];
uint8_t scanRspData[B_MAX_ADV_LEN];
uint8_t *p = scanRspData;
*p++ = sizeof(DEVICE_NAME);
*p++ = GAP_ADTYPE_LOCAL_NAME_COMPLETE;
// unsafe_memcpy(p, DEVICE_NAME, sizeof(DEVICE_NAME));
for (unsigned int i = 0; i < sizeof(DEVICE_NAME) - 1; i++) {
*p++ = DEVICE_NAME[i];
}
unsafe_memcpy(p, DEVICE_NAME, sizeof(DEVICE_NAME) - 1);
*p++ = 11;
*p++ = GAP_ADTYPE_MANUFACTURER_SPECIFIC;
// unsafe_memcpy(p, "BPHS", 4);
*p++ = 'B';
*p++ = 'P';
*p++ = 'H';
*p++ = 'S';
unsafe_memcpy(p, "BPHS", 4);
*p++ = MAJOR_PRODUCT_NUMBER;
*p++ = MINOR_PRODUCT_NUMBER;
*p++ = MAJOR_VERSION_NUMBER;
@@ -555,14 +543,11 @@ static void SimpleBLEPeripheral_taskFxn(UArg a0, UArg a1) {
// message is queued to the message receive queue of the thread or when
// ICall_signal() function is called onto the semaphore.
ICall_Errno errno = ICall_wait(ICALL_TIMEOUT_FOREVER);
// headstage_watchdog_clear();
if (errno == ICALL_ERRNO_SUCCESS) {
ICall_EntityID dest;
ICall_ServiceEnum src;
ICall_HciExtEvt * message = NULL;
if (EVENT_MASK > 0) {
headstage_event_handle();
}
if (ICall_fetchServiceMsg(&src, &dest, (void **)&message) == ICALL_ERRNO_SUCCESS) {
uint8 safeToDealloc = TRUE;
@@ -600,6 +585,10 @@ static void SimpleBLEPeripheral_taskFxn(UArg a0, UArg a1) {
}
}
if (EVENT_MASK > 0) {
headstage_event_handle();
}
#ifdef FEATURE_OAD
while (!Queue_empty(oad_queue_handle)) {
oadTargetWrite_t *oadWriteEvt = Queue_get(oad_queue_handle);
@@ -635,15 +624,7 @@ static uint8_t SimpleBLEPeripheral_processStackMsg(ICall_Hdr *message) {
// Process GATT message
return SimpleBLEPeripheral_processGATTMsg((gattMsgEvent_t *)message);
case HCI_GAP_EVENT_EVENT: { // GAP event
switch (message->event) {
case HCI_EXT_SET_MAX_DATA_LENGTH_EVENT: {
break;
}
default:
break;
}
}
case HCI_GAP_EVENT_EVENT: // GAP event
default:
return TRUE;
}
@@ -678,10 +659,6 @@ static uint8_t SimpleBLEPeripheral_processGATTMsg(gattMsgEvent_t *message) {
} else if (message->method == ATT_MTU_UPDATED_EVENT) {
// MTU size updated
headstage_debug_buffer[10] = 0xff;
headstage_set_debug_information();
} else if (message->method == ATT_HANDLE_VALUE_CFM) {
// quick pass
}
// Free message payload. Needed only for ATT Protocol messages
@@ -710,11 +687,12 @@ static void SimpleBLEPeripheral_sendAttRsp(void) {
// Try to retransmit ATT response till either we're successful or
// the ATT Client times out (after 30s) and drops the connection.
status = GATT_SendRsp(pAttRsp->connHandle, pAttRsp->method, &(pAttRsp->msg));
if ((status != blePending) && (status != MSG_BUFFER_NOT_AVAIL)) {
// Disable connection event end notice
HCI_EXT_ConnEventNoticeCmd(pAttRsp->connHandle, self, 0);
// We're done with the response message
SimpleBLEPeripheral_freeAttRsp(status);
} else {
@@ -761,13 +739,13 @@ static void SimpleBLEPeripheral_freeAttRsp(uint8_t status) {
*/
static void SimpleBLEPeripheral_processAppMsg(sbpEvt_t *message) {
switch (message->hdr.event) {
case SBP_STATE_CHANGE_EVT:
SimpleBLEPeripheral_processStateChangeEvt((gaprole_States_t)message->hdr.state);
break;
case SBP_STATE_CHANGE_EVT:
SimpleBLEPeripheral_processStateChangeEvt((gaprole_States_t)message->hdr.state);
break;
case SBP_CHAR_CHANGE_EVT:
headstage_characteristic_updated(message->hdr.state);
break;
case SBP_CHAR_CHANGE_EVT:
headstage_characteristic_updated(message->hdr.state);
break;
}
}
@@ -795,77 +773,93 @@ static void SimpleBLEPeripheral_stateChangeCB(gaprole_States_t newState) {
*/
static void SimpleBLEPeripheral_processStateChangeEvt(gaprole_States_t newState) {
switch (newState) {
case GAPROLE_STARTED: { // Started but not advertising
uint8_t ownAddress[B_ADDR_LEN];
uint8_t systemId[DEVINFO_SYSTEM_ID_LEN];
case GAPROLE_STARTED: { // Started but not advertising
uint8_t ownAddress[B_ADDR_LEN];
uint8_t systemId[DEVINFO_SYSTEM_ID_LEN];
GAPRole_GetParameter(GAPROLE_BD_ADDR, ownAddress);
GAPRole_GetParameter(GAPROLE_BD_ADDR, ownAddress);
// use 6 bytes of device address for 8 bytes of system ID value
systemId[0] = ownAddress[0];
systemId[1] = ownAddress[1];
systemId[2] = ownAddress[2];
// use 6 bytes of device address for 8 bytes of system ID value
systemId[0] = ownAddress[0];
systemId[1] = ownAddress[1];
systemId[2] = ownAddress[2];
// set middle bytes to zero
systemId[4] = 0x00;
systemId[3] = 0x00;
// set middle bytes to zero
systemId[4] = 0x00;
systemId[3] = 0x00;
// shift three bytes up
systemId[7] = ownAddress[5];
systemId[6] = ownAddress[4];
systemId[5] = ownAddress[3];
// shift three bytes up
systemId[7] = ownAddress[5];
systemId[6] = ownAddress[4];
systemId[5] = ownAddress[3];
DevInfo_SetParameter(DEVINFO_SYSTEM_ID, DEVINFO_SYSTEM_ID_LEN, systemId);
DevInfo_SetParameter(DEVINFO_SYSTEM_ID, DEVINFO_SYSTEM_ID_LEN, systemId);
break;
break;
}
case GAPROLE_CONNECTED: { // In a connection
linkDBInfo_t linkInfo;
uint8_t numActive = 0;
numActive = linkDB_NumActive();
// Use numActive to determine the connection handle of the last
// connection
if (linkDB_GetInfo(numActive - 1, &linkInfo) == SUCCESS) {
} else {
uint8_t peerAddress[B_ADDR_LEN];
GAPRole_GetParameter(GAPROLE_CONN_BD_ADDR, peerAddress);
}
case GAPROLE_CONNECTED: { // In a connection
linkDBInfo_t linkInfo;
uint8_t numActive = 0;
numActive = linkDB_NumActive();
// connected
GAPRole_GetParameter(GAPROLE_CONNHANDLE, &CONNECT_HANDLE);
headstage_led_spi_color(COLOR_CYAN);
/*
headstage_led_spi_color(COLOR_GREEN);
uint16_t cxnHandle;
uint16_t requestedPDUSize = 251;
uint16_t requestTxTime = 2120;
GAPRole_GetParameter(GAPROLE_CONNHANDLE, &cxnHandle);
uint16_t cxnHandle;
uint16_t requestedPDUSize = 251;
uint16_t requestTxTime = 2120;
if (SUCCESS != HCI_LE_SetDataLenCmd(cxnHandle, requestedPDUSize, requestTxTime)) {
}
// Use numActive to determine the connection handle of the last
// connection
if (linkDB_GetInfo(numActive - 1, &linkInfo) == SUCCESS) {
} else {
uint8_t peerAddress[B_ADDR_LEN];
GAPRole_GetParameter(GAPROLE_CONN_BD_ADDR, peerAddress);
}
flag_notify(EVT_CONNECTED);
break;
if(SUCCESS != HCI_LE_SetDataLenCmd(cxnHandle, requestedPDUSize, requestTxTime)) {
}
*/
case GAPROLE_WAITING:
// Device is started but not advertising, is in waiting period before advertising again
SimpleBLEPeripheral_freeAttRsp(bleNotConnected);
break;
flag_notify(EVT_CONNECTED);
break;
}
case GAPROLE_WAITING_AFTER_TIMEOUT:
// Device just timed out from a connection but is not yet advertising, is in waiting period before advertising again
// disconnected
SimpleBLEPeripheral_freeAttRsp(bleNotConnected);
headstage_led_spi_color(COLOR_RED);
CONNECT_HANDLE = 0xFFFF;
case GAPROLE_WAITING: {
// Device is started but not advertising, is in waiting period before advertising again
SimpleBLEPeripheral_freeAttRsp(bleNotConnected);
// disconnected
uint8_t disconnect = CONNECT_HANDLE != CONNECT_HANDLE_UNCONNECTED;
CONNECT_HANDLE = CONNECT_HANDLE_UNCONNECTED;
if (disconnect) {
flag_notify(EVT_DISCONNECTED);
break;
case GAPROLE_ERROR: // Error occurred - invalid state
headstage_led_spi_color(COLOR_RED);
break;
case GAPROLE_INIT: // Waiting to be started
case GAPROLE_ADVERTISING: // Currently Advertising
case GAPROLE_CONNECTED_ADV: // In a connection and advertising
default:
break;
}
break;
}
case GAPROLE_WAITING_AFTER_TIMEOUT:
// Device just timed out from a connection but is not yet advertising, is in waiting period before advertising again
SimpleBLEPeripheral_freeAttRsp(bleNotConnected);
// disconnected over timeout
// TODO headstage_led_spi_color(COLOR_RED);
break;
case GAPROLE_ERROR: // Error occurred - invalid state
// TODO headstage_led_spi_color(COLOR_RED);
break;
case GAPROLE_INIT: // Waiting to be started
case GAPROLE_ADVERTISING: // Currently Advertising
case GAPROLE_CONNECTED_ADV: // In a connection and advertising
default:
break;
}
}
@@ -304,57 +304,57 @@ bStatus_t SimpleProfile_RegisterAppCBs(simpleProfileCBs_t *appCallbacks) {
*/
bStatus_t SimpleProfile_SetParameter(uint8 param, uint8 len, void *value) {
switch (param) {
case SIMPLEPROFILE_CHAR1:
if (len <= SIMPLEPROFILE_CHAR1_LEN) {
memcpy(simpleProfileChar1, value, len);
return SUCCESS;
} else {
return bleInvalidRange;
}
case SIMPLEPROFILE_CHAR1:
if (len <= SIMPLEPROFILE_CHAR1_LEN) {
memcpy(simpleProfileChar1, value, len);
return SUCCESS;
} else {
return bleInvalidRange;
}
case SIMPLEPROFILE_CHAR2:
if (len <= SIMPLEPROFILE_CHAR2_LEN) {
memcpy(simpleProfileChar2, value, len);
return SUCCESS;
} else {
return bleInvalidRange;
}
case SIMPLEPROFILE_CHAR2:
if (len <= SIMPLEPROFILE_CHAR2_LEN) {
memcpy(simpleProfileChar2, value, len);
return SUCCESS;
} else {
return bleInvalidRange;
}
case SIMPLEPROFILE_CHAR3:
if (len <= SIMPLEPROFILE_CHAR3_LEN) {
memcpy(simpleProfileChar3, value, len);
return SUCCESS;
} else {
return bleInvalidRange;
}
case SIMPLEPROFILE_CHAR3:
if (len <= SIMPLEPROFILE_CHAR3_LEN) {
memcpy(simpleProfileChar3, value, len);
return SUCCESS;
} else {
return bleInvalidRange;
}
case SIMPLEPROFILE_CHAR4:
if (len <= SIMPLEPROFILE_CHAR4_LEN) {
memcpy(simpleProfileChar4, value, len);
case SIMPLEPROFILE_CHAR4:
if (len <= SIMPLEPROFILE_CHAR4_LEN) {
memcpy(simpleProfileChar4, value, len);
// See if Notification has been enabled
GATTServApp_ProcessCharCfg(simpleProfileChar4Config, //
simpleProfileChar4,
FALSE,
simpleProfileAttrTbl,
GATT_NUM_ATTRS(simpleProfileAttrTbl),
INVALID_TASK_ID,
simpleProfile_ReadAttrCB);
return SUCCESS;
} else {
return bleInvalidRange;
}
// See if Notification has been enabled
GATTServApp_ProcessCharCfg(simpleProfileChar4Config, //
simpleProfileChar4,
FALSE,
simpleProfileAttrTbl,
GATT_NUM_ATTRS(simpleProfileAttrTbl),
INVALID_TASK_ID,
simpleProfile_ReadAttrCB);
return SUCCESS;
} else {
return bleInvalidRange;
}
case SIMPLEPROFILE_CHAR5:
if (len <= SIMPLEPROFILE_CHAR5_LEN) {
memcpy(simpleProfileChar5, value, len);
return SUCCESS;
} else {
return bleInvalidRange;
}
case SIMPLEPROFILE_CHAR5:
if (len <= SIMPLEPROFILE_CHAR5_LEN) {
memcpy(simpleProfileChar5, value, len);
return SUCCESS;
} else {
return bleInvalidRange;
}
default:
return INVALIDPARAMETER;
default:
return INVALIDPARAMETER;
}
}
@@ -373,28 +373,28 @@ bStatus_t SimpleProfile_SetParameter(uint8 param, uint8 len, void *value) {
*/
bStatus_t SimpleProfile_GetParameter(uint8 param, void *value) {
switch (param) {
case SIMPLEPROFILE_CHAR1:
memcpy(value, simpleProfileChar1, SIMPLEPROFILE_CHAR1_LEN);
break;
case SIMPLEPROFILE_CHAR1:
memcpy(value, simpleProfileChar1, SIMPLEPROFILE_CHAR1_LEN);
break;
case SIMPLEPROFILE_CHAR2:
memcpy(value, simpleProfileChar2, SIMPLEPROFILE_CHAR2_LEN);
break;
case SIMPLEPROFILE_CHAR2:
memcpy(value, simpleProfileChar2, SIMPLEPROFILE_CHAR2_LEN);
break;
case SIMPLEPROFILE_CHAR3:
memcpy(value, simpleProfileChar3, SIMPLEPROFILE_CHAR3_LEN);
break;
case SIMPLEPROFILE_CHAR3:
memcpy(value, simpleProfileChar3, SIMPLEPROFILE_CHAR3_LEN);
break;
case SIMPLEPROFILE_CHAR4:
memcpy(value, simpleProfileChar4, SIMPLEPROFILE_CHAR4_LEN);
break;
case SIMPLEPROFILE_CHAR4:
memcpy(value, simpleProfileChar4, SIMPLEPROFILE_CHAR4_LEN);
break;
case SIMPLEPROFILE_CHAR5:
memcpy(value, simpleProfileChar5, SIMPLEPROFILE_CHAR5_LEN);
break;
case SIMPLEPROFILE_CHAR5:
memcpy(value, simpleProfileChar5, SIMPLEPROFILE_CHAR5_LEN);
break;
default:
return INVALIDPARAMETER;
default:
return INVALIDPARAMETER;
}
return SUCCESS;
@@ -433,31 +433,31 @@ static bStatus_t simpleProfile_ReadAttrCB(uint16_t connHandle, //
// 16-bit UUID
uint16 uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]);
switch (uuid) {
case SIMPLEPROFILE_CHAR1_UUID:
*pLen = SIMPLEPROFILE_CHAR1_LEN;
memcpy(pValue, pAttr->pValue, SIMPLEPROFILE_CHAR1_LEN);
break;
case SIMPLEPROFILE_CHAR1_UUID:
*pLen = SIMPLEPROFILE_CHAR1_LEN;
memcpy(pValue, pAttr->pValue, SIMPLEPROFILE_CHAR1_LEN);
break;
case SIMPLEPROFILE_CHAR2_UUID:
*pLen = SIMPLEPROFILE_CHAR2_LEN;
memcpy(pValue, pAttr->pValue, SIMPLEPROFILE_CHAR2_LEN);
break;
case SIMPLEPROFILE_CHAR2_UUID:
*pLen = SIMPLEPROFILE_CHAR2_LEN;
memcpy(pValue, pAttr->pValue, SIMPLEPROFILE_CHAR2_LEN);
break;
case SIMPLEPROFILE_CHAR4_UUID:
*pLen = SIMPLEPROFILE_CHAR4_LEN;
memcpy(pValue, pAttr->pValue, SIMPLEPROFILE_CHAR4_LEN);
break;
case SIMPLEPROFILE_CHAR4_UUID:
*pLen = SIMPLEPROFILE_CHAR4_LEN;
memcpy(pValue, pAttr->pValue, SIMPLEPROFILE_CHAR4_LEN);
break;
case SIMPLEPROFILE_CHAR5_UUID:
*pLen = SIMPLEPROFILE_CHAR5_LEN;
memcpy(pValue, pAttr->pValue, SIMPLEPROFILE_CHAR5_LEN);
break;
case SIMPLEPROFILE_CHAR5_UUID:
*pLen = SIMPLEPROFILE_CHAR5_LEN;
memcpy(pValue, pAttr->pValue, SIMPLEPROFILE_CHAR5_LEN);
break;
default:
// Should never get here! (characteristics 3 and 4 do not have read permissions)
*pLen = 0;
status = ATT_ERR_ATTR_NOT_FOUND;
break;
default:
// Should never get here! (characteristics 3 and 4 do not have read permissions)
*pLen = 0;
status = ATT_ERR_ATTR_NOT_FOUND;
break;
}
} else {
// 128-bit UUID
@@ -496,59 +496,59 @@ static bStatus_t simpleProfile_WriteAttrCB(uint16_t connHandle, //
uint16 uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]);
switch (uuid) {
case SIMPLEPROFILE_CHAR3_UUID:
case SIMPLEPROFILE_CHAR3_UUID:
// Validate the value
// Make sure it's not a blob oper
if (offset == 0) {
if (len >= SIMPLEPROFILE_CHAR3_LEN) {
status = ATT_ERR_INVALID_VALUE_SIZE;
}
} else {
status = ATT_ERR_ATTR_NOT_LONG;
// Validate the value
// Make sure it's not a blob oper
if (offset == 0) {
if (len >= SIMPLEPROFILE_CHAR3_LEN) {
status = ATT_ERR_INVALID_VALUE_SIZE;
}
} else {
status = ATT_ERR_ATTR_NOT_LONG;
}
// Write the value
if (status == SUCCESS) {
// Copy pValue into the variable we point to from the attribute table.
memcpy(pAttr->pValue + offset, pValue, len);
memset(pAttr->pValue + len, 0, SIMPLEPROFILE_CHAR3_LEN - len);
// Write the value
if (status == SUCCESS) {
// Copy pValue into the variable we point to from the attribute table.
memcpy(pAttr->pValue + offset, pValue, len);
memset(pAttr->pValue + len, 0, SIMPLEPROFILE_CHAR3_LEN - len);
if (pAttr->pValue == simpleProfileChar3) {
notifyApp = SIMPLEPROFILE_CHAR3;
}
if (pAttr->pValue == simpleProfileChar3) {
notifyApp = SIMPLEPROFILE_CHAR3;
}
}
break;
case SIMPLEPROFILE_CHAR5_UUID:
if (offset == 0) {
if (len >= SIMPLEPROFILE_CHAR5_LEN) {
status = ATT_ERR_INVALID_VALUE_SIZE;
}
} else {
status = ATT_ERR_ATTR_NOT_LONG;
break;
case SIMPLEPROFILE_CHAR5_UUID:
if (offset == 0) {
if (len >= SIMPLEPROFILE_CHAR5_LEN) {
status = ATT_ERR_INVALID_VALUE_SIZE;
}
} else {
status = ATT_ERR_ATTR_NOT_LONG;
}
// Write the value
if (status == SUCCESS) {
// Copy pValue into the variable we point to from the attribute table.
memcpy(pAttr->pValue + offset, pValue, len);
memset(pAttr->pValue + len, 0, SIMPLEPROFILE_CHAR5_LEN - len);
// Write the value
if (status == SUCCESS) {
// Copy pValue into the variable we point to from the attribute table.
memcpy(pAttr->pValue + offset, pValue, len);
memset(pAttr->pValue + len, 0, SIMPLEPROFILE_CHAR5_LEN - len);
if (pAttr->pValue == simpleProfileChar5) {
notifyApp = SIMPLEPROFILE_CHAR5;
}
if (pAttr->pValue == simpleProfileChar5) {
notifyApp = SIMPLEPROFILE_CHAR5;
}
}
break;
case GATT_CLIENT_CHAR_CFG_UUID:
status = GATTServApp_ProcessCCCWriteReq(connHandle, pAttr, pValue, len, offset, GATT_CLIENT_CFG_NOTIFY);
break;
break;
case GATT_CLIENT_CHAR_CFG_UUID:
status = GATTServApp_ProcessCCCWriteReq(connHandle, pAttr, pValue, len, offset, GATT_CLIENT_CFG_NOTIFY);
break;
default:
// Should never get here! (characteristics 2 and 4 do not have write permissions)
status = ATT_ERR_ATTR_NOT_FOUND;
break;
default:
// Should never get here! (characteristics 2 and 4 do not have write permissions)
status = ATT_ERR_ATTR_NOT_FOUND;
break;
}
} else {
// 128-bit UUID
@@ -84,7 +84,7 @@ extern "C" {
#define SIMPLEPROFILE_CHAR1_LEN 2
#define SIMPLEPROFILE_CHAR2_LEN 10
#define SIMPLEPROFILE_CHAR3_LEN 20
#define SIMPLEPROFILE_CHAR4_LEN 200
#define SIMPLEPROFILE_CHAR4_LEN 20
#define SIMPLEPROFILE_CHAR5_LEN 20
/*********************************************************************