SIRC P2 FlexBASIC explore
Below is the JonnyMac sirc driver code, not sure, how or where to begin with a FlexBASIC version.
I tried a a very simple start:
dim sirc as class using "jm_sircs_rx.spin2" dim ir_pin% ir_pin% = sirc.start(9) ' Using pin 9 print ": ";ir_pin% ' Print something when the remote key is pressed.
What I would like to do is have a small program that will map the universal remote keys.
Thanks
Ray
'' =================================================================================================
''
'' File....... jm_sircs_rx.spin2
'' Purpose.... Sonry SIRCS protocol receiver
'' Author..... Jon "JonnyMac" McPhalen
'' Copyright (c) 2020 Jon McPhalen
'' -- see below for terms of use
'' E-mail..... jon.mcphalen@gmail.com
'' Started....
'' Updated.... 19 JUL 2020
''
'' =================================================================================================
{{
Example IR Connection (e.g., PNA4602M)
┌───┐
│(*)│ 3.3v
└┬┬┬┘
ir ───┘│└───┘
Note: 500K pull-down can be added to IR input to detect bad/missing sensor
Protocol Reference:
-- http://www.sbprojects.com/knowledge/ir/sirc.php
Bit Formatting:
Command Device Extended
-- 12-bit 6..0 11..7
-- 15-bit 6..0 14..7
-- 20-bit 6..0 11..7 19..12
This object does not include bit error detection (e.g., detect collisions between
multiple IR signals).
}}
con { fixed io pins }
RX1 = 63 { I } ' programming / debug
TX1 = 62 { O }
SF_CS = 61 { O } ' serial flash
SF_SCK = 60 { O }
SF_SDO = 59 { O }
SF_SDI = 58 { I }
con
IR_DISABLE = -1
IR_ENABLE = 0
var
long cog ' cog id
long irpin
long ircode ' rx'd code
long irbits ' bits in code
pub null()
'' This is not a top-level object
pub start(p) : result
'' Start SIRCS receiver on pin p
stop() ' stop if running on another pin
irpin := ircode := p ' set pin
irbits := 2_400 * (clkfreq / 1_000_000) ' ticks in 2.4ms
cog := coginit(COGEXEC_NEW, @rx_sircs, @ircode) + 1 ' start sircs cog
repeat
until (irbits == IR_DISABLE) ' wait for cog to initialize
return cog
pub stop()
'' Stops SIRCS receiver cog if running
if (cog)
cogstop(cog-1)
cog := 0
longfill(@ircode, 0, 2)
pub enable()
'' Enables SIRCS receive process
longfill(@ircode, IR_ENABLE, 2)
pub disable()
'' Disable SIRCS receive process
longfill(@ircode, IR_DISABLE, 2)
pub rx() : result1, result0
'' Enables and waits for ir input
'' -- warning: blocks until IR code received!
'' -- does not remove code/bits from buffer
enable() ' allow ir rx
repeat until (irbits > 0) ' wait for code
return ircode, irbits
pub rxcheck() : result1, result0
'' Returns code and bit count if available, -1 if none
'' -- must have previously been enabled
'' -- does not remove code/bits from buffer
if (irbits > 0) ' if code ready
return ircode, irbits
else
return -1, 0
pub sensor_check() : result
'' Returns true if sensor is pressent
'' -- scans IR input for up to 3ms
'' -- sensor pin should have hi-z (~500K) pull-down
repeat 20
if (pinread(irpin) == 1) ' sensor pin pulled up?
return true ' if yes, sensor is present
waitus(150)
dat { sircs receiver }
org
rx_sircs setq #2-1 ' read pin & timing from hub
rdlong irp, ptra
fltl irp ' clear pin to input state
mov t0, starttix
shr t0, #4 ' t0 = 1/16th starttix
sub starttix, t0 ' test is 15/16ths nominal timing
mov bit1tix, starttix ' "1" bit == 1/2 start bit
shr bit1tix, #1
mov rxcode, ##IR_DISABLE ' tell hub cog is setup
mov bitcount, ##IR_DISABLE
done setq #2-1 ' write results to hub
wrlong rxcode, ptra
wait_enable rdlong t0, ptra ' look for enable signal
tjnz t0, #wait_enable
get_start getct tfall ' mark 1->0
testp irp wc
if_c jmp #get_start ' wait for 1->0 transition
wait_start getct trise ' mark 0->1
testp irp wc
if_nc jmp #wait_start ' wait for 0->1 transition
check_start mov tdelta, trise ' calculate pulse width
subs tdelta, tfall
cmps tdelta, starttix wcz ' validate against start pulse width
if_b jmp #wait_start
mov rxcode, #0 ' clear results
mov bitcount, #0
get_bits getct tdelta ' wait for start of data bit (1->0)
testp irp wc
if_nc mov tfall, tdelta ' detected, mark time & continue
if_nc jmp #wait_bit
subs tdelta, trise ' time-out (end of data bits)?
cmps tdelta, bit1tix wcz
if_b jmp #get_bits
jmp #update_code ' time-out, clean-up bits
wait_bit getct trise ' wait for end of data bit (0->1)
testp irp wc
if_nc jmp #wait_bit
check_bit mov tdelta, trise
subs tdelta, tfall
cmps tdelta, bit1tix wcz
shl rxcode, #1 ' make space for bit
if_a or rxcode, #1 ' write new bit
add bitcount, #1 ' update count
jmp #get_bits
update_code rev rxcode ' correct lsbs
mov tdelta, #32
sub tdelta, bitcount
shr rxcode, tdelta
jmp #done
' -------------------------------------------------------------------------------------------------
irp res 1 ' ir input pin
starttix res 1 ' ticks in start bit
bit1tix res 1 ' "1" bit timing
rxcode res 1 ' recieved SIRCS code
bitcount res 1 ' bits in code
tfall res 1 ' for bit & idle timing
trise res 1
tdelta res 1
t0 res 1 ' work vars
t1 res 1
fit 496
con { license }
{{
Terms of Use: MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be included in all copies
or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}}

Comments
I don't have the hardware to test this, nor am I that familiar with SIRCS, but Jon's code is (as usual) clearly laid out and pretty well documented. The "start()" method returns the number of the helper COG, not a key code. To read the buttons it looks like you need the "rx()" method. So your program would look something like:
Again, I haven't tested this so it may not work as-is, but that's the general gist of how it should go.
As always, when trying to interface with a new Spin device driver, the first step is to read the code and the comments, and figure out roughly what the methods do.
Below is some test code to see if the SIRC is working as expected, yes it is. I left the code that is used for mapping in place.
I mapped the Universal remote that Parallax sells, as follows:
Pwr - 149 ENTER - 139
'1 '- 128 Prev Chnl - 187
'2' - 129 Ch Up - 144
'3'- 130 Ch Dn - 145
'4'- 131 Vol <- - 147 '5'- 132 Vol -> - 146
'6'- 133 MUTE - 148
'7'- 134
'8'- 135
'9' - 136
'0'- 137
Ray
sub ir_remote() 'cognum = sirc.start(9) ' Using pin 9 'print "started cog "; cognum sirc.start(9) do code, bits = sirc.rx() select case code case 144 ' Ch Up key pinhi 57 case 145 ' Ch Dn key pinlo 57 end select 'code, bits = sirc.rx() 'print "received "; bits; " bit long code, value = "; code loop end sub@Ray: You will only be able to read Sony codes with my object -- it won't help you identify any mode that may come out of a universal remote. That said, once you understand how it works, you could write a universal decoder. The IR library used by the Schmarschmino gang does in fact use a mechanism for detecting the IR protocol. This is useful for detecting unknown signals, but very inefficient when you have a known protocol. Once you get a grip on how I'm doing SIRCS receiving, you could probably port the Arduino library code (it's all about measuring pulses and the delays between them).
Here's a video that explains SIRCS transmit and receiving on the P2:
--
I've attached the files discussed during that presentation.