STAF Buttons from left to right: A, B, C. Digits from feft to right: 3, 2, 1, 0. (Different numbering than in the ACTUAL USEFUL MANUAL but the manual was written before serial communication was added) 2 kinds of "modes": "edit" modes for setting up some value "present" mode for showing some value In all edit modes: One digit is selected. All other digits are blinking. Button A: cancel the edit Button B: select next digit; if already last digit then finish editing. Button C: change value of selected digit. In count up or count down mode: Button A: go to next mode Button B: pause / resume Button C: reset In all other modes: Button A: go to next mode Button B & C: go to some edit mode Enter modes by buttons at startup: Button A: calibration Button B: calculator Button C: debug No button: time Order of modes: time date count up count down (edit) At alarm time mode unconditionally changes to alarm mode. MODES In all modes green LED indicates active alarm. alarm: show blinking: hour and minute, "ong" buzzer A, B, C: exit alarm time: show hour and minute. blinking dots. A: date B: edit time C: edit alarm edit time: set new time, hour and minute. A: time edit alarm: set new alarm time, hour minute. If value unchanged but confirmed, clear alarm. A: time date: show date: 3 seconds day and month 1 second year A: countup B: edit date C: edit year edit date: set new date, day and month. A: date edit year: set new year from 0 to 9999 A: date countup: show countup value, minute and second count upwards from 0:00 to 99:59 then loop A: edit countdown B: pause / resume countup C: reset to 0:00 edit countdown: set new countdown value, minute and second blinking dots in downward animation up to 99:59 A: time confirm: countdown countdown: show countdown value, minute and second count down to 0:00 then "o:ng" and buzzer A: edit countdown B: pause / resume countdown C: reset countdown to initial value calibration: show calibration value, hexadecimal, from -FF to FF. double the value is number of clock cycles to add or remove every minute to a 32768Hz clock. negative removes clock cycles (speeds up). positive adds clock cycles (slows down) A: time B: edit calibration edit calibration: set new calibration value, hexadecimal, from -FF to FF. minus sign behaves as an additional digit. A: time calculator: show calculation result. -9.99 to 99.99 with 2 decimal places -999 to 9999 with 0 decimal places "E:EE" otherwise A: reset result to 0; if already 0, then time B: continue calculation, select operator C: new calculation, select operand 1 if "E:EE": A, B, C: reset result to 0 calculator edit operand select a number -9.99 to 99.99 with 2 decimal places -999 to 9999 with 0 decimal places decimal point is selected before the digits (virtual digit 4) top digit can be replaced by '-' (internally digit value A (10)) A: calculator; show last result confirm operand 1: select operator confirm operand 2: calculator; show new result calculator edit operator: select operator: "add", "sub", "mul", "div" A: calculator; show last result confirm: select operand 2; will remember last used value if continued calculation debug: if selected address: show selected address and value at the address, hexadecimal from 0 to FF. real time update if not selected show software version. address range: 00 - 1F: registers of MCP79512 20 - 5F: SRAM of MCP79512 20: alarm flag 21: alarm minute 22: alarm hour 23: countdown flag 24: countdown second 25: countdown minute 26: year flag 27: year low digits 28: year high digits all flags: A5 is true, otherwise fasle A: reset, then time B: edit debug address C: edit debug value edit debug address: set address of register / SRAM memory to read, hexadecimal, from 0 to FF A: debug edit debug value: set value of selected register / SRAM memory address, hexadecimal, from 0 to FF A: debug SERIAL COMMUNICATION 9600bps, 8 data bits, 1 stop bits, no parity, no flow control. Serial transmit line is shared with buzzer. looping 'U' (0x55) is equivalent to 4.8kHz square wave. All communication is human readable. First byte selects command. First byte (command type) is uppercase letter from 'G' to 'R' or lowercase letter from 'g' to 'z'. Receiving the first byte resets any incompletely received previous command Next bytes are data bytes encoded in hexadecimal. So each byte encoded by 2 digits 0 to 9, A to F, a to f. Number of data bytes depends on command type. End of command is CR (0x0D) or LF (0x0A). CR LF will also work but response from STAF will be broken. Response in the same format as command: first byte (command type), data bytes, end. Response starts with the same byte as command. Only uppercase commands have a response. 'G' get time: ask for current time no request bytes 8 response bytes: 0: 0.01s 1: second 2: minute 3: hour 4: day 5: month 6: year, low digits 7: year, high digits all BCD after setting new time the values 0.01s will not be aligned correctly until next full minute (bug of MCP79512)! example: -> G <- G6640241925072220 time is 25.7.2022, 19:24:40.66 'H' get mode: ask for currently active mode no request bytes 1 response byte: 0: mode 00: time 01: alarm 02: date 03: countup 04: countdown 05: calibration 06: version 07: debug 08: reset 09: calculator 80: edit time 81: edit alarm 82: edit date 83: edit year 84: edit countdown 85: edit calibration 86: edit debug address 87: edit debug value 88: calculator edit number 89: calculator edit operator example: -> H <- H02 mode is "date" 'I' get display: ask for state of LCD display will ignore forced value (see 'g' set display) no request bytes 4 response bytes: 0: digit 0, includes upper dot 1: digit 1, includes lower dot 2: digit 2 3: digit 3, includes alarm indicator each bit is 1 segmentl 1 is off, 0 is on. bit order depends on hardware version (see 'N' get pinout) example: -> I <- I202030ff display shows "0:00" 'J' get value ask for presented / edited value no request bytes 3 response bytes: 0: digits 1, 0 1: digits 3, 2 2: digit 4 in some modes the "digits" in software don't match the digits on display example: -> J <- J341200 value on digits is is 0 1 2 3 4 'K' get calculation ask for last calculation result no request bytes 8 response bytes: 0: result, low digits 1: result, high digits 2: operand 2, low digits 3: operand 2, high digits 4: operand 1, low digits 5: operand 1, high digits 6: flags: 01: result is negative 02: result has decimal point 04: operand 2 is negative 08: operand 2 has decimal point 10: operand 1 is negative 20: operand 1 has decimal point C0: operator: 00: + 40: - 80: x C0: : 7: error: 0 is no error, otherwise error, result invalid numbers in BCD example: -> K <- K900241001901d300 -119 / 41 = -2.90 'L' get run mode: ask if countdown / countup is running no request bytes 1 response byte: 0: is running? 00: no 01: yes example: -> L <- L01 the countdown is running 'M' get version ask for software version no request bytes 2 response bytes: 0: minor 1: major example: -> M <- M0302 software version is 2.3 'N' get pinout ask for bit order of segments on display no request bytes 4 response bytes: 0: segments a, b 1: segments c, d 2: segments e, f 3: segments g, h (dot) each value selects bit: 0: 01 1: 02 2: 04 3: 08 4: 10 5: 20 6: 40 7: 80 example: -> N <- N23176054 pinout is: a = 04 b = 08 c = 02 d = 80 e = 40 f = 01 g = 20 h = 10 'O' subscribe for event request staf to send additional response every time an event occurs 1 request byte: 0: events to subscribe for, encoded by bits: 01: a new second (occurs every second) 02: button A pressed 04: button B pressed 08: button C pressed 20: alarm triggered 40: countdown reached 0 1 response byte: 0: detected event, same bits as above example: -> O0E <- O00 <- O04 <- O02 listen for any button press; accepted; pressed button B pressed button A 'P' get alarm ask if alarm is set and at what time no request bytes 2 response bytes: 0: minute 1: hour all BCD FF if no alarm example: -> P <- P2413 alarm at 13:24 -> P <- Pffff no alarm 'Q' get digit ask for currently selected digit no request bytes 1 response byte: 0: digit, from 0 to 4 in some modes the "digits" in software don't match the digits on display example: -> Q <- Q02 digit 2 is selected 'R' read memory read 1 byte from memory of MSP430F1232 2 request bytes: 0: address, low bits 1: address high bits 1 response byte: 0: value example -> R2f02 <- R02 read from address 022F; value is 02 'g' set display force the content of LCD display 4 request bytes: 0: digit 0, includes upper dot 1: digit 1, includes lower dot 2: digit 2 3: digit 3, includes alarm indicator each bit is 1 segmentl 1 is off, 0 is on. bit order depends on hardware version (see 'N' get pinout) will not influence 'I' get display example: -> gef61ffff display ":)" 'h' free display stop forcing the content of LCD display no request bytes example: -> h 'i' trigger event force detecting an event 1 request byte: 0: events to trigger, encoded by bits: 01: a new second 02: button A pressed 04: button B pressed 08: button C pressed not possible to trigger alarm; use 'j' goto mode instead not possible to trigger countdown; use 'w' set value instead; and then trigger 01 example: -> i08 force detecting button C 'j' goto mode force switching to a different mode 1 request byte: 0: mode 00: time 01: alarm 02: date 03: countup 04: countdown 05: calibration 06: version 07: debug 08: reset 09: calculator 80: edit time 81: edit alarm 82: edit date 83: edit year 84: edit countdown 85: edit calibration 86: edit debug address 87: edit debug value 88: calculator edit number 89: calculator edit operator example: -> j01 force trigger an alarm 'k' select digit select which digit should be active 1 request byte: 0: digit, from 0 to 4 in some modes the "digits" in software don't match the digits on display example: -> k02 select digit 2 'l' select digit value set new value for selected digit 1 request byte: 0: digit value, from 0 to F in some modes the "digits" in software don't match the digits on display example: -> l09 set selected digit's value to 9 'm' confirm finish currently acive editing and set the value no request bytes example: -> m 'n' set time set new time, hour and minute 2 request bytes: 0: minute 1: hour all BCD seconds and 0.01s set to 0 after setting new time the values 0.01s will not be aligned correctly until next full minute (bug of MCP79512)! example: -> n2314 set time 14:23 'o' set alarm set new alarm or clear alarm 2 request bytes: 0: minute 1: hour all BCD FF clears alarm example: -> o2512 set alarm to 12:25 -> offff clear alarm 'p' set date set new date, day and month 2 request bytes: 0: day 1: month all BCD example: -> p2306 set date to 23.6 'q' set year set new year 2 request bytes: 0: year, low digits 1: year, high digits all BCD, 0000 to 9999 example: -> q9999 set year 9999 -> q2220 set year 2022 'r' set countdown prepare new countdown valur 2 request bytes: 0: second 1: minute example: -> r5999 set countdown to 59:99 's' set calibration set new calibration value 2 request bytes: 0: value, 00 to FF 1: sign: 00: + 01: - example: -> s0100 set calibration value +01; add 2 clock cycles every minute -> sff01 set calibration value -FF; remove 510 clock cycles every minute 't' set debug address select MCP79512's register / SRAM address to read 1 request byte: 0: address: 00 - 1F: registers of MCP79512 20 - 5F: SRAM of MCP79512 20: alarm flag 21: alarm minute 22: alarm hour 23: countdown flag 24: countdown second 25: countdown minute 26: year flag 27: year low digits 28: year high digits all flags: A5 is true, otherwise fasle example: -> t03 read register 03 (RTCHOUR) 'u' set debug value write to MCP79512's register / SRAM 2 request bytes: 0: value, 00 to FF 1: address: 00 - 1F: registers of MCP79512 20 - 5F: SRAM of MCP79512 20: alarm flag 21: alarm minute 22: alarm hour 23: countdown flag 24: countdown second 25: countdown minute 26: year flag 27: year low digits 28: year high digits all flags: A5 is true, otherwise fasle example -> uff2a write FF to SRAM address 2A 'v' calculate perform a calculation 5 request bytes: 0: operand 2, low digits 1: operand 2, high digits 2: operand 1, low digits 3: operand 1, high digits 4: flags: 04: operand 2 is negative 08: operand 2 has decimal point 10: operand 1 is negative 20: operand 1 has decimal point C0: operator: 00: + 40: - 80: x C0: : numbers in BCD example: -> v41001901d0 calculate -119 / 41 'w' set value set new value for current mode 3 request bytes: 0: digits 1, 0 1: digits 3, 2 2: digit 4 in some modes the "digits" in software don't match the digits on display example: -> w341200 set value 0 1 2 3 4 'x' set run mode start / resume / pause a countdown / countup 1 request byte: 0: run mode: 00: stop 01: run example: -> x01 start the countdown 'y' set buzzer mode enable / disable / force buzzer 1 request byte: 0: buzzer mode: 00: buzzer enabled 01: buzzer disabled 02: buzzer always on useful to remove buzzer ('U') from communication this has no effect on the hardware switch setting which completely disconnects buzzer. example: -> y01 -> j01 -> y00 <- UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU disable buzzer; trigger alarm; (silence); enable buzzer; (buzzer is ON) 'z' write memory write 1 byte to memory of MSP430F1232 3 request bytes: 0: address, low bits 1: address high bits 2: value, 00 to ff example: -> z2f0203 write 03 to address 022F There are no commands to get some values This can be achieved by combining commands: first, select correct state, address, etc. by a command, then, use command 'J' get value finally, select relevant bits from response and decode In almost cases decimal data is stored in BCD format "libstaf" C LIBRARY A C library for communication with the STAF. Will not work on Windows (unless using with Cygwin) libstaf.h and libstaf.c I tried to make the functions and parameters self-explanatory. connect with stafConnent(), it will return an int (file descriptor) to use with all functions, disconnect with stafDisconnect(); Most functions have the same common parameters: int fd: the file descriptor uint8_t *event: a pointer to a single bit int, where any received events will be stored, by bitwise OR with current value uint8_t restoreState: some commands when performed will change the state of the STAF. If !=0 this will read the sete before and restore it after. Not present for commands which don't change the state or should change the state. equivalent to using stafGetState() and stafSetState() Functions return a status. 0 is OK. otherwise not OK. Actual values by pointers. stafConnect(): open a connection with the STAF const char *port: name or the serial port "file" /dev/ttyS0 and so on stafDisconnect(): close the connection with the STAF stafGetState(): get full state, equivalent of running: stafGetMode() stafIsRunning() stafGetDigit() stafGetValue() stafSetState(): restore full state, equivalent of running: stafSetMode() stafSetRunning() stafSetDigit() stafSetValue() in this order; the order is important stafGetMode(): command 'H' stafSetMode(): command 'j' stafCheckEvent(): check if any event notification received, by command 'O' stafSubscribeEvent(): subscribe for event notifications, command 'O' stafTriggerEvent(): command 'i' stafGetPinout(): get display segments bit order, command 'N' stafGetDisplay(): get display content, command 'I' use pinout obtained from stafGetPinout(): uint32_t *display: display content encoded by bits independent of actual pinout: a: 0x01 b: 0x02 c: 0x04 d: 0x08 e: 0x10 f: 0x20 g: 0x40 h: 0x80 digit 3 shifted by 24 bits, digit 2 by 16 bits, digit 1 by 8 bits. stafSetDisplay(): force display content, command 'g' use pinout obtained from stafGetPinout(): display bits encoded as in stafGetDisplay(): stafFreeDisplay(): stop forcing display content, command 'h' stafGetTime(): command 'G' stafSetTime(): command 'n' stafSetDate(): command 'p' stafSetYear(): command 'q' stafGetAlarm(): command 'P' stafSetAlarm(): command 'o' stafClearAlarm(): command 'o' stafSetCountdown(): command 'r' stafIsRunning(): command 'L' stafSetRunning(): command 'x' stafGetVersion(): command 'M' stafGetDigit(): command 'Q' stafSetDigit(): command 'k' stafGetDigitValue(): obtained by commands 'Q' and 'J' stafSetDigitValue(): command 'l' stafGetValue(): command 'J' stafSetValue(): command 'w' stafConfirm(): command 'm' stafSetDebugAddress(): command 't' stafGetDebugValue(): obtained by commands 't', 'i' and 'J' stafSetDebugValue(): command 'u' stafReadMemory(): command 'R' stafWriteMemory(): command 'z' stafSetCalibration(): command 's' stafGetCalibration(): obtained by commands 'j' and 'J' stafSetBuzzerMode(): command 'y' stafCalculate(): commands 'v' and 'K'